原创文章,转载请注明出处:https://starichat.pro/2019/02/16/字符串匹配算法/

字符串匹配算法,在工程中用得很多,我们用到的最多的数据类型恐怕就是字符串了。我们用到的很多函数,诸如 indexOf(),lastIndexOf() 等,他们的底层就需要依赖字符串匹配算法了。

字符串匹配算法很多,先来看看较为简单,易理解的算法吧,他们分别是 BF 算法和 RK 算法。

BF 算法

BF 算法就是暴力**的意思。先定义两个概念:主串和模式串。字符串匹配就是在主串中匹配模式串。
下面来看看 BF 算法定义:
在主串中,检查起始位置分别是 0,1,2…n-m 且长度为 m 的 n-m + 1 个子串,看有没有跟模式串匹配的。如下图:
从 第一个字符开始和主串匹配,每次没有匹配成功,则向后移动一位,再一次执行主串和模式串的匹配,直到匹配成功或者没有找到匹配的字符串。

字符串匹配算法(一)

我们可以发现这个算法的复杂度很高,是O(n*m),但是在实际的开发中,用的还挺多的,理由如下:

  • 实际的软件开发,大部分情况下,模式串和主串的长度都不会太长。而且每次模式串与主串的子串匹配的时候,当中途遇到不能匹配的字符的时候,就可以停止了,不需要把 m 个字符都比对一下。所以,尽管理论上的最坏情况时间复杂度是 O(n*m),但是统计意义上大部分情况下,算法执行效率要比这个高得多。
  • BK 算法思想简单,代码实现也非常简单。简单意味着不容易出错,如果有 bug 也容易暴露和修复。

RK 算法:

在 BK 算法中,我们每一次匹配都需要将模式串的每一个字符和主串进行比较,所以时间复杂度比较高 O(m*n),所以 RK 算法在此基础上进行了优化。

思路是这样的,通过哈希算法对主串的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了。因为哈希值是一个数字,数字之间比较是非常快速的。。所以比较效率就提升了。即不需要通过将每一个模式串和每一个需要匹配的主串进行字符匹配,只用匹配其哈希值就可以了。

但是,我们仍然需要遍历子串中的每个字符,所以我们设计了一个合适的哈希算法来处理这个遍历。

我们假设要匹配的字符串的字符集中只包含K个字符,我们可以用一个K进制数来表示一个子串,这个K进制数转化为十进制数,作为子串的哈希值表述起来有点抽象。

例如:我们要处理az这26个小写字母,那我们就用二十六进制表示一个字符串,我们把az这个26个字符映射到0~25这26个数字,a就表示0,b 就表示 1.。。。。。。

字符串匹配算法(一)

将字符串对应成一个26进制的数,这样将这个26进制的值转换为10进制的数,这个数就是我们所需要的哈希值。

相邻两个子串对应的哈希值计算公式有交集,也就是说,我们可以使用的哈希值s[i-1]很快的计算出s[i]的哈希值,根据设计,我们可以发现RK 可以实现只扫描一遍主串就能计算出所有的子串的哈希值了,所以这部分的时间复杂度是O(n)

字符串匹配算法(一)

模式串哈希值域每个子串哈希值之间的比较的时间复杂度是O(n)。所以 RK 算法整体的时间复杂度就是O(n)

相关文章: