字符串匹配基础

字符串匹配算法

编程语言提供的字符串查找函数,比如 Java 中的 indexOf(),Python 中的 find() 函数等,它们底层就是依赖接下来要讲的字符串匹配算法。

单模式字符串匹配算法有简单的BF 算法和 RK 算法,难懂的BM 算法和 KMP 算法。

多模式字符串匹配算法,就是在一个串中同时查找多个串,有 Trie 树和 AC 自动机。

BF 算法是最简单、粗暴的字符串匹配算法,它的实现思路是,拿模式串与主串中是所有子串匹配,看是否有能匹配的子串。所以,时间复杂度也比较高,是 O(n*m),n、m 表示主串和模式串的长度。不过,在实际的软件开发中,因为这种算法实现简单,对于处理小规模的字符串匹配很好用。

RK 算法是借助哈希算法对 BF 算法进行改造,即对每个子串分别求哈希值,然后拿子串的哈希值与模式串的哈希值比较,减少了比较的时间。所以,理想情况下,RK 算法的时间复杂度是 O(n),跟 BF 算法相比,效率提高了很多。不过这样的效率取决于哈希算法的设计方法,如果存在冲突的情况下,时间复杂度可能会退化。极端情况下,哈希算法大量冲突,时间复杂度就退化为 O(n*m)。

BF 算法

BF (Brute Force)算法,中文叫作暴力匹配算法,也叫朴素匹配算法。这种算法的字符串匹配方式很“暴力”,比较简单、好懂,但相应的性能也不高。

主串模式串的概念:比如在字符串 A 中查找字符串 B,那字符串 A 就是主串,字符串 B 就是模式串。

设主串的长度为n,模式串的长度为m,因为在主串中查找模式串,所以 n>m。

BF 算法的思想就是,穷举主串中起始位置分别是 0、1、2…、n-m 且长度为 m 的 n-m+1 个子串,看有没有跟长度为m的模式串匹配的:

1570498286430

1570498286430

BF 算法每次都比对 m 个字符,最坏情况下要比对 n-m+1 次,所以最坏情况时间复杂度是 O(n*m)。

BF 算法虽然相对其他字符串匹配算法,时间复杂度高,但却是一个最常用的字符串匹配算法,因为大部分情况下,模式串和主串的长度都不会太长。另外BF算法思想简单,代码实现简单不容易出错,即使有 bug 也容易暴露和修复。

在工程中,在满足性能要求的前提下,简单是首选。这也是KISS(Keep it Simple and Stupid)设计原则

所以,绝大部分情况下,BF 朴素的字符串匹配算法就够用了。

python实现代码:

def bf(main, pattern) -> int:
    """bf暴搜    :param main: 主串    :param pattern: 模式串    :return:    """    n = len(main)
    m = len(pattern)
    if n <= m:
        return 0 if pattern == main else -1    for i in range(n - m + 1):
        for j in range(m):
            if main[i + j] != pattern[j]: break            if j == m - 1: return i
    return -1