目录
- 前言废话
- 暴力搜索
- KMP算法
前言废话
最近脑子有点昏昏沉沉,喝点那种红枣泡的白酒居然神奇的好了一些,感觉很舒服。看来喝少量的酒可以让人更清醒,长期喝可能有养生的效果? 写道这里去百度了下,发现红枣还真有养生效果。对于长期坐在电脑旁的人,不止眼睛,其实整个身体状况就注定不会很好,平时还是要注意养生。虽然现在整个行业很卷又是互联网的寒冬,但还是尽量抽出一点时间出去走走运动运动,这样人更精神做事效率也会更高。前段时间有个大佬左耳朵才40多岁就心梗去世了,应该是平时没注意自己身体或者没有精力管自己的身体健康问题?从某种程度上来说,程序员这个职业已经是一种高危职业了,有中年失业危机以及伴随的中年死亡危机。。
虽然这行各种危机,但是单纯的写代码还是能够从中获得乐趣,这算是代码给人的一点福利吧。
暴力搜索
废话说完回到正题,说到字符串搜索,最简单直接的大家都能想到的一种:暴力搜索。但是这种搜索算法大家都知道它的效率是比较低的,时间复杂度O(M * N)。
暴力搜索过程,如下图:
代码:
public boolean searchStr(String text,String p){
if(text == null || text.equals("")|| p == null||p.equals("") )return false;
int i = 0,j = 0;
while (i <text.length()) {
if(text.charAt(i) == p.charAt(j)){
if(j == p.length()-1){
System.out.println("找到了:"+text.substring(i-j,i+1));
return true;
}
j++;
i++;
}else{
i= i-j+1;
j=0;
}
}
return false;
}
从上面的动态图可以看出来,暴力搜索做了很多重复搜索的工作。还是以动态图的数据为例:
字符串匹配了:edc三个字符最后一个没有匹配上。又要从已经搜索过的字符串中再重新比对,这就导致了在文本搜索的过程中存在大量的重复搜索过程。如果在一个大型文本中搜索特定的字符串,用这个算法来做搜索那就是一个灾难了。
KMP算法
上面提到暴力搜索算法效率低的原因是,要重复搜索已经搜索过的字符。那有没有一种算法可以解决这个问题呢?KMP算法就是解决这个问题的一种方法。KMP算法搜索文本的指针只会一直向前不会回退,这就解决了暴力搜索时指针回退造成的重复搜索问题。
在kmp算法遇到字符串没有被完全匹配时,要求k指针
回到正确的位置,而指向文本的指针i
保持不变。然后继续比较p[k]与text[i]的值。
问题:如何找到模式串P匹配失败之后 指针K
应该回到哪个位置上呢?
在ababb
匹配文本字符串时,可能匹配了:a ab aba abab
因此要分别找这些字符串的最长公共前后缀。
public int[] next(String p){
int[] next = new int[p.length()];
if(p.length() <2)return next;
int i = 1,k =0;
while (i < p.length()) {
if(p.charAt(i) == p.charAt(k)){
k++;
next[i++] = k;
}else {
if(k ==0)i++;
else k=0;
}
}
return next;
}
public boolean kmp(String text,String p){
int[] next = next(p);
int k = 0;
int searchCount = 0;
for(int i = 0;i <text.length(); ){
searchCount++;
if(text.charAt(i) == p.charAt(k)){
if(k == p.length()-1){
System.out.println("kmp搜索次数:"+searchCount);
return true;
}
k++;
i++;
}else{
if(k!= 0)
k = next[k-1];
else
i++;
}
}
System.out.println("kmp搜索次数:"+searchCount);
return false;
}
求next数组有点技巧,但是不太好用语言来描述,我当时是手动画图来理解next应该怎样生成。想了很久也没有想出一个通俗易懂的方式来表达,可能最好的方式就是画图理解吧。至于kmp的主体搜索过程就很简单了,和暴力搜索过程差不多,不过不用回退文本指针i,并且k指针,也是直接用next数组可以得到。