#P2716. 第1题-小红的字符串
-
1000ms
Tried: 94
Accepted: 18
Difficulty: 2
所属公司 :
阿里
时间 :2025年3月20日-阿里云(开发岗)
-
算法标签>字符串
第1题-小红的字符串
题解
题面描述
给定一个字符串s和一个正整数k(1≤k≤10),以及q个询问。对于每个询问给定一个字符串t,若t的某个前缀或后缀(要求长度至少为k)是s的子串,则输出“YES”,否则输出“NO”。
思路
首先,我们通过遍历字符串s提取出所有长度为k的子串并存入集合,然后对于每个查询字符串t,若其长度不小于k,只需判断t的前k字符或后k字符是否存在于集合中,从而高效地确定是否满足条件。
观察题目条件,对于任一字符串t,其所有长度至少为k的前缀都拥有相同的前k个字符,同理,所有后缀都拥有相同的后k个字符。因此,判断t是否满足条件,只需要检查t的前k字符和后k字符是否出现在s中即可。
具体步骤如下:
- 预处理:遍历s,提取所有长度为k的连续子串,将其存入哈希集合(或其他快速查询数据结构)中。
- 查询:对于每个询问字符串t,若∣t∣<k则必然不满足;否则,取t的前k字符和后k字符,检查是否存在于预处理得到的集合中,满足任一条件则输出“YES”,否则输出“NO”。
这种方法利用了题目中k较小的性质,降低了查询时的复杂度,并且整体时间复杂度为O(∣s∣+∑∣t∣)。
C++
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;
int main(){
ios::sync_with_stdio(false); // 加速输入输出
cin.tie(nullptr);
string s;
cin >> s;
int q, k;
cin >> q >> k;
// 预处理:将字符串 s 中所有长度为 k 的子串存入集合
unordered_set<string> substrSet;
int len = s.size();
for(int i = 0; i <= len - k; i++){
substrSet.insert(s.substr(i, k)); // 截取从 i 开始的长度为 k 的子串
}
// 处理每个查询
while(q--){
string t;
cin >> t;
// 如果 $ t $ 长度小于 k ,则无法构成符合要求的前缀或后缀
if(t.size() < k){
cout << "NO\n";
continue;
}
// 获取 t 的前 k 字符串和后 k 字符串
string pre = t.substr(0, k);
string suf = t.substr(t.size() - k, k);
// 判断是否存在于 s 的子串集合中
if(substrSet.count(pre) || substrSet.count(suf))
cout << "YES\n";
else
cout << "NO\n";
}
return 0;
}
Python
def main():
import sys
# 读取所有输入数据
input_data = sys.stdin.read().split()
s = input_data[0]
q = int(input_data[1])
k = int(input_data[2])
# 预处理:构造 s 中所有长度为 k 的子串集合
substrSet = set()
for i in range(len(s) - k + 1):
substrSet.add(s[i:i+k])
index = 3 # 后续数据的起始下标
res = []
for _ in range(q):
t = input_data[index]
index += 1
# 若 t 长度小于 k ,则直接输出 "NO"
if len(t) < k:
res.append("NO")
else:
# 获取 t 的前 k 和后 k 子串
pre = t[:k]
suf = t[-k:]
# 判断是否存在于 s 的子串集合中
if pre in substrSet or suf in substrSet:
res.append("YES")
else:
res.append("NO")
# 输出所有结果
sys.stdout.write("\n".join(res))
if __name__ == '__main__':
main()
Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
// 使用 BufferedReader 加速输入读取
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 读取字符串 s
String s = br.readLine().trim();
// 读取第二行:询问次数 q 和长度限制 k
String[] secondLine = br.readLine().trim().split(" ");
int q = Integer.parseInt(secondLine[0]);
int k = Integer.parseInt(secondLine[1]);
// 预处理:将 s 中所有长度为 k 的子串加入 HashSet
HashSet<String> set = new HashSet<>();
for (int i = 0; i <= s.length() - k; i++){
set.add(s.substring(i, i + k));
}
StringBuilder sb = new StringBuilder();
// 处理每个查询
for (int i = 0; i < q; i++){
String t = br.readLine().trim();
// 如果 t 的长度小于 k ,则输出 "NO"
if(t.length() < k){
sb.append("NO\n");
} else {
// 获取 t 的前 k 和后 k 子串
String pre = t.substring(0, k);
String suf = t.substring(t.length() - k);
// 判断是否存在于 s 的子串集合中
if(set.contains(pre) || set.contains(suf))
sb.append("YES\n");
else
sb.append("NO\n");
}
}
// 输出所有结果
System.out.print(sb);
}
}
题目内容
小红很喜欢字将串s,如果字符串t的某一个长度至少为k的前缀或某一个长度至少为k的后缀是s的子串,那么小红也会喜欢字符串t。
例如,k=2时,小红喜欢字符串hello那么小红也喜欢字符"ciallo",“he”,因为“ciallo”的长度为2的后缀"lo""he"的长度为2的前缀“he”都是“hello”的子串,但小红不喜欢字符串“soyo",因为"soyo”的任何一个前缀、后缀都不是“hello”的子串。
小红有一个字符串喜欢的s,她每次会问你,字符串t她是否喜欢。
输入描述
第一行输入一个长度不超过105的只由小写字母构成的字符串。
第二行输入两个正整数q(1≤q≤105),k(1≤k≤10)表示询问次数和长度限制,
接下来q行,每行输入一个只由小写字母构成的字符串t表示询问。
数据保证,所有的字符串t的长度之和不超过105
输出描述
对每个询问输出一行,若小红喜欢字符串t,输出“YES”,否则输出"NO"
样例1
输入
hello
3 2
ciallo
he
soyo
输出
YES
YES
NO