每天一道算法题——字符串匹配
来源:互联网 发布:网络电视十大排行榜 编辑:程序博客网 时间:2024/06/06 08:54
字符串匹配算法是我在公司面试时候的一道算法题,当时用的还是最基本的暴力枚举法写出来的吧,之前看过的KMP算法,Rabin-Karp算法都没用上,今天就来总结一下字符串匹配的几种算法吧。
一、暴力匹配法:
这应该是万能算法了,但性能比较差,它的过程就是在[0,n-m]范围内,查找是否存在一个s,0<=s<=m,是得P[1..m] = T[s+1,...,s+m]。最坏情况下外层for循环次数为n-m+1, 内层for循环执行m次,所以算法复杂度是O(m(m-n+1))。
代码如下:
package p_14_matchstr;public class MatchString {public int match1(String P, String T) {for(int i=0; i<T.length()-P.length(); i++) {for(int j=0; j<P.length(); j++) {if(P.charAt(j) == T.charAt(i+j) && j == P.length()-1) {return i;}else if(P.charAt(j) != T.charAt(i+j)) {break;}}}return -1;}public static void main(String[] args) {// TODO Auto-generated method stub String T = "abcabaabcabac"; String P = "abaa"; RabinKarp rk = new RabinKarp(T, P, 26, 29); MatchString ms = new MatchString(); System.out.println(ms.match1(P, T)); int s = rk.matchRK(); System.out.println("Valid shift is: "+ s);}}
二、进阶版 Rabin-Karp版本:该算法在实际运用中,表现不错,RK算法需要O(m) 时间做预处理,在最坏情况下,该算法的复杂度与枚举法一样都是,O((n - m + 1) m).但在实际运用中,最坏情况极少出现。
对于一个长度为m的字符串P[1…m],用p表示该字符串对应的含有m个数字的整形数,我们用ts 来表示T[s+1, … , s+m] 这m个字符对应的整形数值,不难发现,当两个数值相等时,这两个数值对应的字符串就相等,也就是当且仅当p = ts 有 P[1…m] = T[s+1,…,s+m]。
将字符串转换成数字:p = P[m] + 10(P[m-1]+10(P[m-2]+...+(10P[2]+P[1])...)
如果不是该字符串,计算下一个数ts1,公式:
计算一次的复杂度为O(1), 计算t0,... ,tn-m是需要O(n - m + 1),所以时间复杂度O(n-m+1)。
但是这个方法有一个缺点,就是如果数非常大的情况下可能会导致溢出。(当两个过大的数值比较大小时,CPU需要多个运算周期来进行,这样两数比较,我们就不能假定他们可以在单位时间内完成了。处理这种情况的办法可以采用求余。但是p,ts求余后又会引入新问题:数值相等但是字符串不匹配。这就需要在两个求余后的数相等的情况下,再去逐个匹配每个字符。
代码实现:
package p_14_matchstr;public class RabinKarp {private String T, P;private int d, q;private int n, m;private int k = 1;public RabinKarp(String T, String P, int d, int q) {this.T = T;this.P = P;this.d = d;this.q = q;n = T.length();m = P.length();for(int i=0; i<m; i++){k = k*d;k %= q;}}public int matchRK(){int p = 0;int t = 0;for(int i=0; i<m; i++){p = (d*p + (P.charAt(i) - 'a')) % q;t = (d*t + (P.charAt(i) - 'a')) % q;}for(int i=0; i<n-m; i++){if(p == t){for(int j=0; j<m; j++){if(j == m-1 && P.charAt(j) == T.charAt(j+i)) {return i;}else if(P.charAt(j) != T.charAt(j+i)){break;}}}else{t = (d*(t-k*(T.charAt(i)-'a'))+T.charAt(i+m)-'a')% q;if(t < 0){t += q;}}}return -1;}}
阅读全文
0 0
- 每天一道算法题——字符串匹配
- 每天一道算法题——每天一道算法题
- 每天一道算法题——汉诺塔
- 每天一道算法题——
- 每天一道算法题(21)——字符串的全排列和组合算法
- 每天一道算法题(7)——在字符串中删除特定的字符
- 每天一道算法题(25)——字符串中连续出现次数最多的子串
- 每天一道算法题(26)——输入字符串表达式求值
- 每天一道算法题(29)——检测字符串的是否由移位得到
- 每天一道算法题(35)——删除字符串首尾的空格
- 【每天一道算法题】
- 【每天一道算法题】
- 【每天一道算法题】
- 每天一道算法题(16)——翻转链表
- 每天一道算法题(22)——扑克牌的顺子
- 每天一道算法题(23)——约瑟夫环问题
- 每天一道算法题(31)——正数减法
- 每天一道算法题(34)——背包问题
- 生产者消费者模型中Queue理解
- tomcat linux service 服务
- css控制文字行数,超出部分用省略号代替
- google的地址搜索
- JDK8Lambda要点
- 每天一道算法题——字符串匹配
- ZendStudio使用
- Unity_确认栏
- spring1
- TracerPid反调试实现与逆向
- 部分C语言运算符优先级
- javaWeb服务器在linux上的搭建
- 自定义控件的点点滴滴
- PAT