📌  相关文章
📜  检查给定字符串是否存在给定模式(1)

📅  最后修改于: 2023-12-03 14:55:50.229000             🧑  作者: Mango

检查给定字符串是否存在给定模式

当需要在一个字符串中查找特定的子串时,就需要进行字符串模式匹配。在计算机科学中,一般有两类字符串模式匹配算法,一种是基于暴力匹配的朴素算法,另一种是基于自动机的KMP算法。

朴素算法

朴素算法是一种简单粗暴的字符串匹配算法,基于字符串中每一个字符与子串首字符的比较,在发现第一个匹配字符后进行接下来字符的匹配。如果发现不匹配字符,则回到原字符串的下一个位置继续匹配。如果字符串后面部分无法匹配,则将子串向后移一位并从头重新开始。

朴素算法的时间复杂度为O(nm),其中n为主串长度,m为子串长度,当子串和主串完全不符合时,需要比较n-m+1次。

def naive_search(pattern, text):
    matches = []
    n, m = len(text), len(pattern)
    for i in range(n - m + 1):
        j = 0
        while j < m and text[i+j] == pattern[j]:
            j += 1
        if j == m:
            matches.append(i)
    return matches
KMP算法

KMP算法是一种更快的字符串匹配算法,基于预处理模式串中的信息,尽可能避免在主串中回溯匹配字符。在KMP算法中,主要是利用匹配失败时的信息,即在匹配失败后不回到主串起始位置,而是从模式串中重新寻找匹配位置。

KMP算法的时间复杂度为O(n+m),其中n为主串长度,m为子串长度,最坏情况下需要比较2n次。

def kmp_table(pattern):
    n = len(pattern)
    prefix = [-1] * n
    j = -1
    for i in range(1, n):
        while j >= 0 and pattern[j+1] != pattern[i]:
            j = prefix[j]
        if pattern[j+1] == pattern[i]:
            j += 1
        prefix[i] = j
    return prefix

def kmp_search(pattern, text):
    matches = []
    n, m = len(text), len(pattern)
    prefix = kmp_table(pattern)
    j = -1
    for i in range(n):
        while j >= 0 and pattern[j+1] != text[i]:
            j = prefix[j]
        if pattern[j+1] == text[i]:
            j += 1
        if j == m - 1:
            matches.append(i - m + 1)
            j = prefix[j]
    return matches
总结

朴素算法虽然简单易懂,但是在长字符串和长模式串的匹配中会非常低效,因此通常使用KMP算法来进行字符串匹配。KMP算法的主要思想在于通过预处理模式串,尽可能利用已经匹配的信息,减少回溯的次数。