举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”?
1、字符串”BBC ABCDAB ABCDABCDABDE”的第一个字符与搜索词”ABCDABD”的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。
2、因为B与A不匹配,搜索词再往后移。
3、就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。
4、接着比较字符串和搜索词的下一个字符,还是相同。
5、直到字符串有一个字符,与搜索词对应的字符不相同为止。
6、这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把”搜索位置”移到已经比较过的位置,重比一遍。
7、一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是”ABCDAB”。KMP算法的想法是,设法利用这个已知信息,不要把”搜索位置”移回已经比较过的位置,继续把它向后移,这样就提高了效率。
8、借助最长公共前缀后缀长度数组,将模式串向左移动合适的位置。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std ;
int next[100] ;
void getNext( char p[] ) {
int len = strlen(p) ;
next[0] = 0 ;
int i = 0 , j = 0 ;
for(j = 1 ; j < len ; j++) { // i 代表最长前缀后缀长度
while( p[i] != p[j] && i > 0 ) // 当p[i] != p[j] 时,减小最长前缀后缀长度
i = next[i-1] ;
if(p[i] == p[j]) {
i++ ; //最长公共前缀后缀长度+1
next[j] = i ; //匹配失败时跳到该处
}
else
next[j] = 0 ;
}
}
int main() {
char p[100] ;
cin >> p ;
int lenp = strlen(p) ;
getNext(p);
char s[1000] ;
getchar() ;
gets(s) ;
int lens = strlen(s) ;
int j = 0 ;
bool flag = false ;
for(int i = 0 ; i < lens ; i++) {
if(p[j] == s[i])
j++ ;
else if(j-1 >= 0)
j = next[j-1] ;
if(j == lenp) {
flag = true ;
j = i ;
break ;
}
}
cout <<"结束位置:"<< j+1 << endl ;
if(flag)
cout << "YES" << endl ;
else
cout << "NO" << endl ;
return 0 ;
}