算法五——字符串匹配(上)

文章内容、图片均来自极客时间。

如何借助哈希算法实现高效字符串匹配

1 概念和用途

字符串匹配:查找一个字符串A在字符串B中是否出现,这个过程就是字符串匹配。A称为模式串,B称为主串。主串的长度记为n,模式串长度记为m。 n > m n>m n>m
在java中有String的indexOf用就是字符串匹配。
字符串匹配有基础的BF算法、高效的KMP算法。

2 BF算法

BF=Brute Force 暴力搜索
  算法思想:在主串中,分别从起始位置0,1,2…n-m且长度为m的n-m+1个子串是否和模式串相同。

  从算法过程分析,最坏时间复杂度是O(nm)。例如主串是“aaaa…aaa”(省略符号表示有若干个a)。模式串是"aaaab"。因为有n-m+1个子串,每次比较m次。比较总次数是 ( n − m + 1 ) ∗ m = n ∗ m − m 2 + m (n-m+1)*m=n*m-m^2+m (nm+1)m=nmm2+m,记为O(nm)。
  BF尽管时间复杂度比较高,但在实际应用中经常使用。原因有二。
  第一,在实际应用中字符串都比较短,每次两个字符串比较的时候遇到不相同的字符,就可以提前返回。所以实际比n*m要少。
  第二,算法思想简单,实现简单,不容易出错。这也符合KISS(Keep it simple and stupid)原则。在工程中,满足性能的前提下,简单是原则。

3 RK算法

RK=Rabin-Karp,是该算法的两位提出者。
  在BF算法中,两次字符串比较,因为要比较m次,复杂度较高。如果为每个字符串计算一个哈希值,每次比较哈希值,复杂度就可能会降低。
  算法思想:对模式串求哈希值。对n-m+1个主串中的子串分别求哈希值,然后逐个和模式串的哈希值比较。因为哈希值是一个数字比较非常快。但是因为求哈希所以整体算法效率没有提高。
  改进:可以通过改进求子串哈希值,降低时间复杂度。假如字符串中只包含a-z这26个字母,每个字母分别对应数字0~25。哈希值采用26进制表示。
  例如: " d b c " = d ∗ 26 ∗ 26 + b ∗ 26 + c = 3 ∗ 26 ∗ 26 + 1 ∗ 26 + 2 = 2056 "dbc" = d*26*26+b*26+c=3*26*26+1*26+2=2056 "dbc"=d2626+b26+c=32626+126+2=2056
  这种哈希方法相邻子串哈希值是有特点的。可以使用前一个子串的哈希值计算下一个子串的哈希值。
  
  记h1=hash(dbc)=32626+126+2,h2=hash(bce)=12626+226+4.
  A=126+2
  B=1
2626+226
  那么B=26*A
  令h[i-1]表示(i-1,i+m-2)子串的哈希值,h[i]表示(i,i+m-1)子串的哈希值。那么
   h [ i ] = ( h [ i − 1 ] − 2 6 m − 1 ( s [ i ] − ′ a ′ ) ) ∗ 26 + ( s [ i + m − 1 ] − ′ a ′ ) h[i]=(h[i-1]-26^{m-1}(s[i]-'a'))*26+(s[i+m-1]-'a') h[i]=(h[i1]26m1(s[i]a))26+(s[i+m1]a)
  这里还可以提高的地方时,可以提前把 2 6 0 26^0 260, 2 6 1 26^1 261,… 2 6 m − 1 26^{m-1} 26m1存入数组中。次方就是数组下标,便于查询。

时间复杂度分析
  计算哈希值主要扫描一遍主串即可,时间复杂度O(n)。计算子串与模式串哈希值比较是否相同,时间复杂度O(1),共需要n-m+1次比较, 时间复杂度O(n)。总体时间复杂度时间复杂度O(n)。

字符串很长,哈希值超出能表示的范围怎么办?
  上面的设计完全没有哈希冲突,当允许有哈希冲突,会不会解决呢?上面的算法是进位相乘,如果改为加法,数值就小很多了。例如 " d b c " = 3 + 1 + 2 = 6 "dbc"=3+1+2=6 "dbc"=3+1+2=6。这样的话取值范围小多了,但哈希冲突概率会很高。如果每个字母不对应整数,而是对应从小到大不同的素数,这样哈希冲突的概率就会降低了。

如果有哈希冲突了,怎么办?
  当两个字符串哈希值相同的时候,就挨个字符串比较,确保字符串真的相同。只是如果这样,当冲突概率很高的时候,RF比BF的效率还低。因为还要计算哈希。

4 思考题

上面讲的是一维字符串的比较,如果是主串和模式串都是一个二维矩阵,怎么匹配呢?
   
  解决思路:可以将二维矩阵转为一个数组,变成一维的,再比较。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值