从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,有 si=si+len。这表示字符串从第 len 个字符开始的部分与前 n−len 个字符完全相同。

通过KMP的next数组,我们可以快速检查这一点。具体来说:

  • 计算字符串的next数组

  • 对于每个可能的长度 len,如果 s 的前 n−len 个字符与从 len 开始的 n−len 个字符完全匹配,那么 len 是一个候选

  • 我们需要找到最小的这样的 len

相关推荐
mykj15514 小时前
英语单词APP解锁学习新方式,智能高效背单词
学习·英语单词app
知识分享小能手5 小时前
深度学习学习教程,从入门到精通,深度学习中的正则化 — 完整知识点与代码示例(7)
人工智能·深度学习·学习
find1star5 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
迅翼SwiftWing5 小时前
编队系列(总)|固定翼编队如何实现稳定飞行?通信架构、协同算法与工程约束深度解析
算法·架构
LB21125 小时前
力扣160 21 86
算法·leetcode·职场和发展
~kiss~6 小时前
Agent 的 未来吗?String: An Agentic OS Where Every App Is a Markdown File
学习
小智老师PMP6 小时前
2026深度解析|PMP第八版与NPDP核心侧重点本质区别(管理类证书怎么选)
开发语言·分布式·算法·职场和发展·产品经理
HugoStudio_SWAN6 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
a187927218316 小时前
【算法】动态规划第二篇:双序列 DP 三课——继承、计步与断链
算法·leetcode·动态规划·dp·回溯·暴力·算法讲解
江畔柳前堤7 小时前
前台·中台·后台:2026年AI原生时代的架构全景图
开发语言·人工智能·算法·机器学习·架构·scala·ai-native