今天介绍两种基础的字符串匹配算法,当然核心还是熟悉一下Go的语法,巩固一下基础知识

  • BF(Brute Force)
  • RK(Rabin Karp)

源字符串:src, 目标字符串:dest; 确认dest是否是src 的一部分。

BF算法很简单暴力,维护两个下标i,j,i控制src的遍历顺序, j控制dest遍历顺序。
记录一下i的起始位置,当j和i所在的字符匹配的时候,j和i都移动,知道j达到末尾则直接返回匹配。
否则i 回到起始位置的下一个位置,j 回到起始位置,两者重新进行匹配搜索。

由于比较简单,直接看一下Go实现的代码即可:

func Brute_force(str1 string, str2 string) bool{if len(str1) < len(str2){return  false}var (begin int = 0 // 维护src的起始位置i intj int)for i = 0; i < len(str1); begin++ {for j = 0;j < len(str2); j++ {if i < len(str1) && str1[i] == str2[j] {i++continue} else {break}}if j == len(str2) {return  true}i = begini++}return false
}

以上最坏的情况下是 主串是“aaaaa…aaaaaa”(省略号表示有很多重复的字符a),模式串是“aaaaab”。我们每次都比 对m个字符,要比对n-m+1次,所以,这种算法的最坏情况时间复杂度是O(n*m)。
当然这种模式匹配在实际的软件开发中还是比较常用的,主要有如下两种原因:

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

接下来看一下第二种算法,Rabin Karp。
这个算法的大体思路是:
过哈希算法对主串中的n-m+1个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相 等,那就说明对应的子串和模式串匹配了。因为哈希值是一个数字,数字之间比较是否相等是非常快速的, 所以模式串和子串比较的效率就提高了。

为了提升效率,我们需要尽可能避免遍历字符串中的每一个字符,否则就是仅仅提高了比较效率而已(数值的比较效率)。
hash函数的设计需要精巧一些,假设我们设置的字符集只包含k个字符,我们可以使用一个K进制的数来表示一个字符串,将这个 K进制转化为10进制的值即可作为hash 值。

比如要处理的字符串包括a-z 26个字母,我们可以使用26进制表示一个字符串,同时将26进制转化为一个10进制的值作为这个字符串的hash值。

对于字符串:“hjk”
h: (‘h’- ‘a’) *26^0
j: (‘j’ - ‘a’) * 26^1
j: (‘k’ - ‘a’) * 26^2

hash(“hjk”) = (‘h’- ‘a’) *26^0 + (‘j’ - ‘a’) * 26^1 + (‘k’ - ‘a’) * 26^2

为了减少遍历源字符串中的字符 次数,我们可以看看如下规律:
源字符串“hjkl”,我们先取 “hjk”, 后取"jkl"

hash(“hjk”) = (‘h’- ‘a’) *26^0 +('j' - 'a') * 26^1 + ('k' - 'a') * 26^2
hash(“jkl”) = ('j' - 'a') * 26^0 + ('k' - 'a')* 26^1 + (‘l’ - ‘a’) * 26^2

依据此规律,我们可以总结出来两个公式:
hash(i-1) = 26^0 * (s[i-1] - ‘a’) + 26^1 * (s[i] - ‘a’) + … + 26^(m-1) * (s[i+m-2] -‘a’)
hash(i) = 26^0 * (s[i] - ‘a’) + … + 26^(m-2) * (s[i + m - 2] - ‘a’) + 26^(m-1) * (s[i+m-2] -‘a’)

i表示源字符串的起始遍历位置字符下标,m表示目标字符串的长度, s表示源字符串 src。

两个公式进行运算:hash(i) - hash(i-1) / 26 = 26^(m-1) * (s[i+m-2] -‘a’) - (26^0 * (s[i-1] - ‘a’)) / 26
最终可以得到: hash(i) = (hash(i-1) - s[i-1] -‘a’ ) / 26 + 26^(m-1) * (s[i+m-2] -‘a’) 这样的计算公式。

这个时候,我们只需要扫描一遍主串即能够完成目标字符串的匹配, 主串的长度为n, 也就是我们需要O(n)的扫描复杂度。模式串的hash值 和每一个子串的hash值之间的比较是O(1) , 总共需要比较n-m+1个子串的哈希值,所以,这部分的时间复杂度也是O(n)。

所以,RK算法整体的时间复杂度就是O(n),相比于BF的O(m*n)效率还是高了不少

Go语言的完整实现如下:

// Calculate a string's hash function
func Hash(str string, m [] int) int {if len(str) == 0 {return 0}var (t intres int = 0)for i := 0; i < len(str); i ++ {t = m[i] * int(str[i] - 'a')res = res + t}return res
}// match the substring with hash function
// we can calculate the string's hash value with below formula
//
// 's' is source string, m is the length of the substring
// h(i-1) = 26^0 * (s[i-1] - 'a') +
//          26^1 * (s[i] - 'a') + ... +
//          26^(m-1) * (s[i+m-2] -'a')
//
// h(i) = 26^0 * (s[i] - 'a') + ... +
//        26^(m-2) * (s[i + m - 2] - 'a') +
//        26^(m-1) * (s[i+m-2] -'a')
//
// so
// h(i) = (h(i-1) - s[i-1] -'a' ) / 26 + 26^(m-1) * (s[i+m-2] -'a')
// we can use the formula to reduce the cpu's calculation
func Rabin_Karp_Hash(str1 string, str2 string) bool {if len(str1) < len(str2) {return false}var m []intvar t int = 1m = append(m,1)for i := 1; i < len(str2) + 1; i ++ {t = t*26m = append(m,t) // m store with 26^0, 26^1, 26^2 ... 26^(len(str2))}str2_hash := Hash(str2, m)fmt.Println(str2_hash)str1_hash := Hash(string([]byte(str1)[:len(str2)]),m)if str2_hash == str1_hash {return  true}for i := 1; i < len(str1) - len(str2) + 1; i ++ {new_hash := (str1_hash - int(str1[i-1]-'a')) / 26 +m[len(str2)-1] * int(str1[i+len(str2) -1] - 'a')if new_hash == str2_hash {return  true} else {str1_hash = new_hash}}return  false
}

Go 语言实现字符串匹配算法 -- BF(Brute Force) 和 RK(Rabin Karp)相关推荐

  1. 【GO语言实现字符串匹配算法-KMP算法】

    [GO语言实现字符串匹配算法-KMP算法] KMP算法原理说明: KMP算法是一种改进的字符串匹配算法,是有D.E.Knuth,J.H.Morris和V.R.Pratt提出的,所以被称为KMP算法. ...

  2. 字符串匹配算法BF,BM,KMP

    字符串匹配bf算法:(暴力穷举算法) 在一个字符串中寻找另一字符串,最容易想到的,也是最简单的办法是:取主串和模式串/搜索串中的每一位依次比较,如果匹配则同时后移一位继续比较,直至匹配到模式串的最后一 ...

  3. python实现字符串匹配算法BF,BF改,KMP

    包含:BF,BF改进版本,KMP BF:暴力搜索 BF改:当判断匹配失败的字符串是不是与首字母相同 若不同,继续BF算法: 若相同,直接将首字母移到当前位置 KMP:通过前缀与后缀发现待匹配字符串本身 ...

  4. 字符串匹配KMP算法设计C语言,KMP字符串匹配算法笔记

    网上有很多解释KMP算法的文章,A_B_C_ABC的这篇很详细,反复看了好几遍,总算理解了个大概,但是总觉得没那么爽快.其实,一种算法各人有各人的理解方法,找到适合自己理解的才容易记住.下面是我对这个 ...

  5. 字符串匹配算法---BF及KMP

    字符串匹配的一般算法(BF)     以 ABSABABCEF 与 ABCE 为例,求串2与串1匹配的第一个位置的下标(这里即输出 5),一般的,我们可以从串1的起始位置开始与串2比较,若相同则两串都 ...

  6. 字符串匹配算法 -- BM(Boyer-Moore) 和 KMP(Knuth-Morris-Pratt)详细设计及实现

    文章目录 1. 算法背景 2. BM(Boyer-Moore)算法 2.1 坏字符规则(bad character rule) 2.2 好后缀规则(good suffix shift) 2.3 复杂度 ...

  7. 列宽一字符等于多少厘米_字符串匹配算法总结——BF、KMP、BM

    说明 以下算法介绍中,被匹配字符串称为主串,匹配模式字符串称为匹配串,索引从0开始. 前缀数组:字符串S = AB(B !== ⏀,即B为任一非空字符串) ,S的前缀指A.前缀数组指所有包含第一个字符 ...

  8. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  9. iptables --algo 字符串匹配算法 bm kmp

    http://blog.csdn.net/l953972252/article/details/51331001 字符串匹配一直是计算机领域热门的研究问题之一,多种算法层出不穷.字符串匹配算法有着很强 ...

最新文章

  1. 【MATLAB】三维图形的绘制mesh
  2. 完成登录功能,用session记住用户名
  3. 原创 | 常见损失函数和评价指标总结(附代码)
  4. border-raduis 在IE8中的兼容性问题
  5. 《Spark大数据分析:核心概念、技术及实践》一3.6 惰性操作
  6. 01.CSS动画--transform
  7. python基础----python的使用(四)
  8. Pearson相关系数 - Pearson's Correlation Coefficient
  9. 宜搭小技巧|找不到应用怎么办?群应用一键直达
  10. 基于docker使用jenkins集成sonar
  11. 当我们在讨论机器学习时我们在说些什么?
  12. 学了这么久的高并发编程,连Java中的并发原子类都不知道?这也太Low了吧
  13. 计算机与网络期刊多少钱,《计算机与网络》是不是核心期刊
  14. 电商十二、pinyougou02.sql的内容③
  15. hdu5294||2015多校联合第一场1007 最短路+最大流
  16. 橡皮擦的英语_小朋友们知道“橡皮擦”用英语该怎么说吗?
  17. Linux基于rhel的DNS部署(一)——高速缓存DNS
  18. 微信瑞文智力测试1分_答完瑞文智力测试的题之后,怎样看智商是多少?
  19. 普通打印机,双面打印技巧
  20. VMTK【1】Getting Started

热门文章

  1. Java中的文件上传2(Commons FileUpload:commons-fileupload.jar)
  2. maven插件报错之解决
  3. SharePoint使用BCS开发你第一个应用程序(三)
  4. 《帝企鹅日记》观后感
  5. [Ubuntu] 安装/卸载 声卡驱动
  6. 《OpenCV3编程入门》学习笔记7 图像变换(三 )重映射
  7. python测试程序的qps和响应时间代码_Python并发请求下限制QPS(每秒查询率)的实现代码...
  8. c语言计算M=11 22 33,四川计算机C语言考试笔试真题33次..doc
  9. java类引用接口的注释_java – 在接口类型上使用注释有什么好处?
  10. java tablemodel_高级组件——表格模型TableModel