写在开头的话
学习了今天的基础知识,让我们来做几道题来练练手吧。如果有不懂的可以看看写在文末的思路讲解(题目是别的地方扒来的,参考答案是我自己写的,肯定不是最优解,有更好的方法欢迎评论区交流)
第一题------KMP匹配字符串

第二题------最小循环覆盖长度

参考答案
第一题参考答案(Python版)
python
def kmp_search(pattern, text):
"""
使用 KMP 算法在 text 中搜索 pattern 的所有出现位置
返回所有起始下标(从 0 开始)
"""
n = len(pattern)
m = len(text)
# 构建部分匹配表(next 数组)
lps = [0] * n # lps 表示最长前缀后缀匹配长度
j = 0 # pattern 的指针
for i in range(1, n):
while j > 0 and pattern[i] != pattern[j]:
j = lps[j - 1]
if pattern[i] == pattern[j]:
j += 1
lps[i] = j
# KMP 搜索
result = []
j = 0 # pattern 的指针
for i in range(m): # i 是 text 的指针
while j > 0 and text[i] != pattern[j]:
j = lps[j - 1]
if text[i] == pattern[j]:
j += 1
if j == n: # 找到一个完整匹配
result.append(i - n + 1)
j = lps[j - 1] # 继续搜索下一个可能匹配
return result
def main():
# 读取输入
n = int(input().strip())
pattern = input().strip()
m = int(input().strip())
text = input().strip()
# 检查长度是否符合题目要求(虽然输入已经保证,但可以作为健壮性检查)
if n > m:
print()
return
# 使用 KMP 搜索
positions = kmp_search(pattern, text)
# 输出结果
if positions:
print(' '.join(map(str, positions)))
else:
print() # 如果没有匹配,输出空行(题目未明确,但通常如此)
if __name__ == "__main__":
main()
第二题参考答案(Python版)
python
def min_cycle_cover(s):
n = len(s)
# 计算next数组
next_arr = [0] * n
j = 0
for i in range(1, n):
while j > 0 and s[i] != s[j]:
j = next_arr[j - 1]
if s[i] == s[j]:
j += 1
next_arr[i] = j
# 查找最小循环覆盖长度
# 从n开始递减检查每个可能的长度
for len_val in range(1, n + 1):
# 检查前n-len_val个字符是否与从len_val开始的n-len_val个字符相同
# 这等价于检查next[n]是否至少为n-len_val
if next_arr[n - 1] >= n - len_val:
# 进一步验证:对于所有i < n-len_val,s[i]应该等于s[i+len_val]
# 我们可以通过检查前缀函数来验证
valid = True
for i in range(n - len_val):
if s[i] != s[i + len_val]:
valid = False
break
if valid:
return len_val
return n
def main():
s = input().strip()
result = min_cycle_cover(s)
print(result)
if __name__ == "__main__":
main()
思路讲解
第一题------KMP匹配字符串
算法说明
-
构建部分匹配表(LPS 数组):
-
LPS 数组存储了模式串每个位置的最长相同前缀后缀的长度
-
用于在匹配失败时跳过不必要的比较
-
-
KMP 搜索过程:
-
遍历文本串,与模式串进行比较
-
当字符匹配时,两个指针都向前移动
-
当字符不匹配时,根据 LPS 数组回退模式串指针
-
当模式串完全匹配时,记录起始位置,并继续搜索
-
-
时间复杂度:
-
构建 LPS 数组:O(N)
-
KMP 搜索:O(M)
-
总复杂度:O(N + M),在本题数据规模下完全可行
-
第二题------最小循环覆盖长度
我们需要找到最小的 len,使得对于所有 0≤i<n−len,有 s[i]=s[i+len]。这表示字符串从第 len 个字符开始的部分与前 n−len 个字符完全相同。
通过KMP的next数组,我们可以快速检查这一点。具体来说:
-
计算字符串的next数组
-
对于每个可能的长度 len,如果 s 的前 n−len 个字符与从 len 开始的 n−len 个字符完全匹配,那么 len 是一个候选
-
我们需要找到最小的这样的 len