从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

相关推荐
Xの哲學12 小时前
Linux SMP 实现机制深度剖析
linux·服务器·网络·算法·边缘计算
wuk99812 小时前
使用PCA算法进行故障诊断的MATLAB仿真
算法·matlab
知识分享小能手12 小时前
Ubuntu入门学习教程,从入门到精通,Ubuntu 22.04的Linux网络配置(14)
linux·学习·ubuntu
额呃呃12 小时前
二分查找细节理解
数据结构·算法
无尽的罚坐人生13 小时前
hot 100 283. 移动零
数据结构·算法·双指针
永远都不秃头的程序员(互关)13 小时前
C++动态数组实战:从手写到vector优化
c++·算法
手揽回忆怎么睡13 小时前
Streamlit学习实战教程级,一个交互式的机器学习实验平台!
人工智能·学习·机器学习
xiaoxiaoxiaolll13 小时前
《Advanced Materials》基于MXene的复合纤维实现智能纺织品多模态功能集成
学习
水力魔方14 小时前
武理排水管网模拟分析系统应用专题5:模型克隆与并行计算
数据库·c++·算法·swmm
db_murphy14 小时前
学习篇 | 英方i2Active和i2Stream工具了解
学习