数据结构学习总结:
一、KMP简介
kmp算法,也就是用于字符串匹配中的一种算法。(即解决一个主串中是否包含给定子串)
- 普通暴力解法:在两个字符串匹配过程中,当遇到不匹配时,匹配串需要往后挪一位,从头开始重新再匹配。时间复杂度为O(N*M) (N为主串的长度,M为匹配串的长度)
- 而KMP算法,是为了在不匹配的时候,能让匹配串多往后挪几位。加速匹配。将时间复杂度降为O(N)
二、代码实现
2.1 思路:
(1) 首先要理解一个概念。
即=》某一个字符的前缀和后缀匹配的最长长度。
假设子串为abcabck,那么k字符位置之前的字符串的前缀和后缀匹配的最长长度为3.
同理,如果字符串为aaaaaab。那么b位置时的前缀和后缀匹配时的最长长度为5.
(2) 假设要在abcdedfdfdg中查找能匹配abkm的子串。那么我们就对abkm中的每一个字符建立刚刚1中所说的最长匹配长度。
即分别在a,b, k, m各个位置建立各个字符的前缀和后缀匹配的最长长度。最后的结果就会对应一个数组。先叫它next[4] 数组。假设字符串为aabad。那么该对应的next数组就是[-1,0,1,0,1];(最前面的a字符前没有字符,人为规定它的前缀和后缀匹配时的最长长度为-1).
(3) 现在我们有next[]数组(具体求解算法,稍后再详细说。现在只需要先理解next[]所包含的信息是什么意思即可)。那么如何利用next[]数组来加速匹配过程,即 在不匹配时可以一次性往后多挪几位。
用next[] 数组加速实现原理如下:
KMP解法下:
…
2.2 代码
(1)主串和子串匹配过程的代码
/**
* 两个字符串的匹配过程
*
* @param s 主串
* @param m 模式串
* @return 返回匹配的第一个字符位置
*/
public int getRes(String s,String m){
if(s==null || m==null || m.length()>s.length()){
return -1;
}
char[] str = s.toCharArray();
char[] match =m.toCharArray();
int x=0;//表示str中当前比对的位置
int y=0;//表示match中当前比对的位置
int[] next = getNextArray(match);//表示match中第i个字符前的前缀和后缀匹配的最大长度
while(x<str.length && y<match.length){
if(str[x] == match[y]){
x++;
y++;
}else if(next[y] ==-1){ //说明match数组在第一个位置的字符就不匹配
x++;
}else{//主串中当前比对位置不变,子串的比对位置变动
y=next[y];
}
}
return y==match.length?x-y:-1;
}
(2) next数组的生成
private int[] getNextArray(char[] match) {
int[] next =new int[match.length];
if(match.length==0){
return new int[]{-1};
}
next[0] =-1;//人为规定
next[1] =0;
int i =2;
int cn =0;//和当前i-1位置比对的位置.初始值为0.因为当前i在2.i-1就为1.那么与1位置比较的位置就是0位置
while(i<match.length){
if(match[i-1]==match[cn]){
next[i] =cn;
i++;//求下一个next i
cn++;
}else if(cn>0){
cn = next[cn];
}else{
next[i++] =0;
}
}
return next;
}