从0开始学算法——第十二天(KMP算法练习)

写在开头的话

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

第一题------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匹配字符串

算法说明

  1. 构建部分匹配表(LPS 数组)

    • LPS 数组存储了模式串每个位置的最长相同前缀后缀的长度

    • 用于在匹配失败时跳过不必要的比较

  2. KMP 搜索过程

    • 遍历文本串,与模式串进行比较

    • 当字符匹配时,两个指针都向前移动

    • 当字符不匹配时,根据 LPS 数组回退模式串指针

    • 当模式串完全匹配时,记录起始位置,并继续搜索

  3. 时间复杂度

    • 构建 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

相关推荐
云小逸18 小时前
【nmap源码学习】 Nmap网络扫描工具深度解析:从基础参数到核心扫描逻辑
网络·数据库·学习
咖丨喱19 小时前
IP校验和算法解析与实现
网络·tcp/ip·算法
罗湖老棍子20 小时前
括号配对(信息学奥赛一本通- P1572)
算法·动态规划·区间dp·字符串匹配·区间动态规划
fengfuyao98520 小时前
基于MATLAB的表面织构油润滑轴承故障频率提取(改进VMD算法)
人工智能·算法·matlab
机器学习之心20 小时前
基于随机森林模型的轴承剩余寿命预测MATLAB实现!
算法·随机森林·matlab
一只小小的芙厨20 小时前
寒假集训笔记·树上背包
c++·笔记·算法·动态规划
庄周迷蝴蝶20 小时前
四、CUDA排序算法实现
算法·排序算法
以卿a20 小时前
C++(继承)
开发语言·c++·算法
I_LPL20 小时前
day22 代码随想录算法训练营 回溯专题1
算法·回溯算法·求职面试·组合问题
盐焗西兰花21 小时前
鸿蒙学习实战之路-Reader Kit构建阅读器最佳实践
学习·华为·harmonyos