字符串匹配算法--数据结构与算法之美--CH32

文章目录

  • 1. 什么是字符串匹配
  • 2. 如何实现字符串匹配
    • 2.1 BF算法
      • 2.2.1 BF算法常用原因
    • 2.2 RK算法
      • 2.2.1 hash 算法的设计
      • 2.2.2 散列冲突处理
  • 3. 其他算法简介
  • 4. 思考总结

1. 什么是字符串匹配

  “字符串匹配”就是在一个长字符串A中搜索一个短的字符串B,此时A称为主串,B称为模式串
  把主串A的长度记作 n,模式串B的长度记作 m,因为在主串中查找模式串,所以 n>m。

2. 如何实现字符串匹配

  现实开发中,很多语言都内置了字符串匹配算法,java中的indexOf(),python中的find(),而本节要学习的是这些算法的底层实现。

2.1 BF算法

  BF(Brute Force)算法是一种暴力匹配算法,其思想一句话概括:在主串中检查起始位置分别是0,1,2…n-m且长度为m的n-m+1个子串,看有没有跟模式串匹配的。如下图所示:
字符串匹配算法--数据结构与算法之美--CH32_第1张图片

时间复杂度分析
  每个模式串长度为m,最坏情况下要比较n-m+1次,因此时间复杂度为 O ( n ∗ m ) O(n*m) O(nm)

2.2.1 BF算法常用原因

  尽管BF算法的时间复杂度很高,但是他有两个优点,使得其很常用。

  1. 实际开发中,模式串和主串都不会太长,而且大部分查找,找到了可以提前终止,因此统计学意义上的效率比较高。
  2. 朴素匹配算法思想简单,算法不容易出错,因此工程上满足性能前提下,简单就是首选。

2.2 RK算法

  RK算法基于BF算法进行优化,利用hash算法将主串中的n-m+1个子串分别求hash值,然后利用hash值就行比较,这样省去了逐个字符比较。不考虑hash冲突的情况下,如下图所示:
字符串匹配算法--数据结构与算法之美--CH32_第2张图片

RK算法时间复杂度
  模式串与子串hash值比较时间复杂度为 O ( 1 ) O(1) O(1),共需要比较n-m+1次,因此时间复杂度为 O ( n ) O(n) O(n)

2.2.1 hash 算法的设计

  由于计算子串hash值时需要遍历每个字符,尽管模式串与子串比较效率提高了,但是算法整体效率并没提高。因此需要对hash算法进行合理设计。
  比如要处理的字符串只包含 a~z 这 26 个小写字母,那就用二十六进制来表示一个字符串。把 a~z 这 26 个字符映射到 0~25 这 26 个数字,a 就表示 0,b 就表示 1,以此类推,z 表示 25。计算如下图所示,对比十进制:
字符串匹配算法--数据结构与算法之美--CH32_第3张图片
  这样设计的hash算法,相邻两个子串s[i-1]和s[i]的hash值有一定规律,计算完成s[i-1]可以很快算出s[i],如下图所示:
字符串匹配算法--数据结构与算法之美--CH32_第4张图片
  由于每次计算 2 6 ( m − 1 ) 26^(m-1) 26(m1),因此可以做预处理,将 2 6 0 26^0 260 2 6 ( m − 1 ) 26^(m-1) 26(m1)存入数组中,每次计算查表即可,省去了计算时间。
  这里体现出了一种思想,通过运算规律减少运算量,通过预处理减少运算量

2.2.2 散列冲突处理

  上述hash算法设计固然好且一定不会出现散列冲突,但是如果字符串长度较长,则会导致超出计算机的整型值范围。这时候就需要折中设计一套相对简单,允许有hash冲突的算法。
  比如要处理的字符串只包含 a~z 这 26 个小写字母,把 a~z 这 26 个字符映射到 0~25 这 26 个数字,a 就表示 0,b 就表示 1,以此类推,hash算法将其字母相加。
  或者也可以见a-z的字符映射到素数,这样冲突概率会进一步降低。
  此时,遇到hash冲突的时候,在使用BF的强匹配就可以了。

3. 其他算法简介

  除了上述两种字符串匹配算法,还有经典的BM算法,KMP算法,Trie树,AC自动机。

  1. BM算法和KMP算法两者基于BF算法进行优化,主要思路是BF算法每次向后移动以为,而BM利用“坏字符”和“好后缀”可以移动多位,KMP算法利用“坏字符”和“好前缀”移动多位。
  2. Trie树是一种多模式匹配算法,Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起,形成一个多叉树,方便查找。主要应用于前缀匹配的字符串查找,比如“搜索引擎关键词提示功能”。
  3. AC 自动机是多模式匹配算法,单模式串匹配算法是为了快速在主串中查找一个模式串,而多模式串匹配算法是为了快速在主串中查找多个模式串。他是基于 Trie 树的一种改进算法,它跟 Trie 树的关系,就像单模式串中,KMP 算法与 BF 算法的关系一样。

4. 思考总结

  字符串匹配算法的演进,其实就是一个典型的算法优化过程以及数据结构不断迭代的过程。

  1. 时间复杂度大,先减少不必要的比较操作,然后里边具体的操作、查找,通过散列表或者预处理来优化。
  2. 通过移动多位,减少比较次数。
  3. BF到KMP的演进思想,next数组又应用到了Trie树到AC自动机的优化。

  这种演进思路,是以时间和空间复杂度为优化目标的迭代,这种优化思想是可以迁移到很多应用场景的。

你可能感兴趣的:(数据结构和算法,字符串匹配,RK算法,BF算法)