#include<iostream>
using namespace std;
int* Next(string T){
int i = 0,j = 1;
int tlen = T.length();
int *N = new int[tlen];
N[0] = 0;
int counter = 1;
while(j < tlen){
if(T[i] == T[j]){
N[counter] = 1+N[counter -1];
i+=1;
j+=1;
counter += 1;
}
else{
if(i == 0){
N[counter] = 0;
counter+=1;
j+=1;
}
else{
while(T[j] != T[i]&& i >0)
i = N[i];
if(T[j] == T[i]){
N[counter] = N[i] + 1;
j+= 1;
i+=1;
counter += 1;
}
else{
N[counter] = 0;
j+=1;
counter += 1;
}
}
}
}
return N;
}
int KMP(string T,string P,int pos){ //实际上是KMP的变式,可以由pos所指示的位置开始查找
int p = 0,t = pos;
int plen = P.length();
int tlen = T.length();
if(tlen < plen)
return -1;
int *n = new int[plen];
n = Next(T);
/* cout << "向量数组为:" ;
for(int i = 0;i<tlen;i++)
cout << n[i] << " ";
cout << endl;*/
while(t<tlen&&p<plen){
if(T[t]==P[p]){
t+=1;
p+=1;
}
else{
if(p != 0)
p = n[p-1];
else
t += 1;
}
}
if(p == plen)
return t-p;
else
return -1;
}
static int POS = 0;
int Search(string Str,string Substr){
int res = -1;
int i = 0;
int len = Str.length();
while(POS < len){
i = KMP(Str,Substr,POS);
POS += 1;
if(i != -1)
res = i;
}
return res;
}
int main(){
string P,T;
cout << "请输入目标字符串:" ;
cin >> T;
cout << endl << "请输入模式字符串:";
cin >> P;
int i = 0;
i = Search(T,P);
if(i==-1)
cout << endl << "模式串不是目标串的子串!" << endl;
else
cout << endl << "模式串在目标串中最后一次出现的位置:" << i << endl;
return 0;
}
这个代码一开始想的是写一个KMP的变式,可以在指定的位置开始查找字串,然后在另一个函数中多次调用这个变式函数,得到最终结果。
后来我又想了一下其实没必要这么麻烦的。。只不过是把KMP算法改一下,如果匹配成功,则记录子串出现的位置,然后回溯,回到子串出现的位置的后一位,这样不断修改子串出现的位置,最终结果就是子串最后一次出现的位置啦!
修改后的代码在这里啦:
int KMP2(string str,string subst){
int i = 0,j = 0,pos = -1;
int* next = new int[subst.length()];
Next(subst,next);
for(int m = 0;m < subst.length();m++)
cout << next[m] << " ";
while(i < str.length()){
if(str[i] == subst[j]){
if( j == subst.length()-1){
pos = i -j;
j = 0;
i = i-j+ 1; //这里很关键哦!
}
else{
i += 1;
j += 1;
}
}
else{
if(j!= 0)
j = next[j];
else
i += 1;
}
}
return pos;
}