返回

字符串匹配算法:大道至简,代码至美

见解分享

在计算机科学的世界中,大道至简的原则同样适用。本文将探究字符串匹配算法的精髓,用最简洁优雅的代码实现最强大的功能。

从日常应用到复杂的搜索引擎,字符串匹配算法无处不在。Java 的 indexOf() 方法、JavaScript 的 find()、indexOf() 和 includes() 函数都依赖于底层的字符串匹配算法。

本文将深入揭秘四种字符串匹配算法,从简单到复杂,让您领略算法之美:

1. 暴力匹配算法

暴力匹配算法是最简单直接的算法。它从字符串的开头逐个字符与模式进行比较,直到找到匹配项或遍历完整个字符串。

def暴力匹配(s, p):
    for i in range(len(s) - len(p) + 1):
        if s[i:i+len(p)] == p:
            return i
    return -1

2. KMP 算法

KMP 算法(Knuth-Morris-Pratt 算法)在暴力匹配算法的基础上进行了改进。它利用模式的失配信息,在发生失配时快速跳过不必要的比较,从而提高效率。

def KMP(s, p):
    n, m = len(s), len(p)
    fail = [0] * m
    j = 0
    for i in range(1, m):
        while j > 0 and p[i] != p[j]:
            j = fail[j - 1]
        if p[i] == p[j]:
            j += 1
        fail[i] = j
    i, j = 0, 0
    while i < n:
        if p[j] == s[i]:
            i += 1
            j += 1
        elif j > 0:
            j = fail[j - 1]
        else:
            i += 1
        if j == m:
            return i - j
    return -1

3. Boyer-Moore 算法

Boyer-Moore 算法是一种基于模式字符位置查找的算法。它利用模式中的字符位置信息,在发生失配时快速跳过大量不必要的比较,效率比 KMP 算法更高。

def BoyerMoore(s, p):
    n, m = len(s), len(p)
    last = {}
    for i in range(m):
        last[p[i]] = i
    i = m - 1
    while i < n:
        j = m - 1
        while j >= 0 and s[i] == p[j]:
            i -= 1
            j -= 1
        if j < 0:
            return i + 1
        i += max(1, j - last.get(s[i], -1))
    return -1

4. 有限状态自动机算法

有限状态自动机(FSA)算法是一种基于状态转换的算法。它将字符串匹配的过程转换为状态转换图,通过不同的状态转换来判断是否存在匹配项。

def 有限状态自动机(s, p):
    m = len(p)
    states = [0] * (m + 1)
    x = 0
    for j in range(1, m + 1):
        while x > 0 and p[x] != p[j]:
            x = states[x - 1]
        if p[x] == p[j]:
            x += 1
        states[j] = x
    j = 0
    for i in range(len(s)):
        while j > 0 and s[i] != p[j]:
            j = states[j - 1]
        if s[i] == p[j]:
            j += 1
        if j == m:
            return i - m + 1
    return -1

通过对这四种算法的深入分析,我们领悟了算法之美:大道至简,代码至美。在不同的场景下,选择合适的算法可以极大地提高字符串匹配的效率。