KMP专题总结

KMP算法有两种计算失配函数的方法

未优化过的失配函数 , f[i] 就表示 str[0~i-1] 的公共最长前后缀( 不包括str[0~i-1]本身,比如aaa的最长公共前后缀长度为2 ) , 这个特性必须牢记

从下面的例子应该也可以看出

0  1  2  3  4  5  6  7  8  9  10

str  a  a  a  a  b  b  a  a  b  a  ‘\0’

f   0  0  1  2  3  0  0  1  2  0   1

优化过后的失配函数,虽然匹配的性能要好点 , 不过失去上述这么优美的特性 , 基本也就是废了( 应该不至于出道裸的匹配,然后卡失配函数吧 )

=========================================我是分割线=================================================

模板和原理我就不赘述了,网上资料很多,贴个模板完事

未优化的失配函数

void get_nex( char * str ){
	int len = strlen( str ) ;
	f[0] = 0 , f[1] = 0 ;
	for( int i = 1 ; i < len ; i ++ ) {
		int j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		// 跟某个前缀匹配成功,那么下次从下个前缀可以匹配
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		// 否则从头开始匹配
		else f[i+1] = 0 ;
	}
}

KMP 匹配函数

int KMP( char * str , char * sub_str ) {
	int len1 = strlen( str ) , len2 = strlen( sub_str ) ;
	// 当前跟子串的那个字符匹配
	int j = 0 ;
	int ans = 0 ;
	for( int i = 0 ; i < len1 ; i ++ ) {
		// 如果成功下次匹配下一个字符 , 否则一直沿失配边走
		while( j && str[i] != sub_str[j] ) j = f[j] ;
		if( str[i] == sub_str[j] ) j ++ ;
		if( j == len2 ) j = f[j] , ans ++ ;
	}
	return ans ;
}

=====================================我是华丽丽的分割线==============================================

比较常见的问题 ( 应该要熟练掌握 ) :

1. KMP 求出 S[0...i-1] 的所有的公共前后缀的问题

这个东西在某些题目中会用于统计

很显然 , f[i] 的值就是 S[0...i-1] 的最长公共前后缀 ( 还是一样不包括串本身的 ),因为那个华丽丽的特性

然后怎么求稍微短一点的 ? 仔细一想,s[0...i-1] 次长( 存在的话 ) 的公共前后缀 ,就是 s[0...i-1] 和 s[i-f[i],i-1] 的最长公共前后缀。

那么又因为s[i-f[i],i-1] 本身就是原串是 s[0,f[i]-1] , 所以次长的公共前后缀就是 f[f[i]] 了

后面的就以此类推就行

2. KMP 求循环串

什么是 循环串 就是某个字符串可以由它的前缀重复几次得到这个串本身 。比如 aabaabaabaab ,可以有 aab , aabaab , aabaabaabaab 循环得出

假设我们称 aab , aabaab 这样的为循环节

那么怎么求最长的循环节呢 ?  len - f[len] 就是循环节的长度 ,当然要同时满足 len % ( len - f[len] )  == 0

假设字符串的长度为 len ,len - f[len] = K ,  K * t = len

那么根据上述结论 , 整个字符串就应该是由 t 个 s[0...K-1] 循环组成的 ,如何得到这个呢 ?

S[0...K-1] , S[K,2*K-1] ...................... S[(t-1)*K,t*K-1 ]

S[0,K-1]  , S[K,2*K-1] ..... S[(t-2)*K,(t-1)*K-1] , S[(t-1)*K,t*K-1]

因为我们知道 f[len] = len - K , 也就是说 字符串的前 ( t-1) * K 个字符串和 后( t - 1 ) * K 个字符串的相等的

那么我们就可以得到 S[0,K-1] == S[K,2*K-1] .... S[(t-1)*K,t*K-1] = S[(t-2)*K,(t-1)*K-1]

所以我们很容易得到 S[0,K-1] == S[K,2*K-1] = ... =
S[(t-1)*K,t*K-1]

OK,我们已经得到答案了

至于再大一点的循环节,我们只要求小一点的最长公共前后缀就行了。

=====================================又是华丽丽的分割线==============================================

KMP题目 :

POJ 3461 Oulipo

POJ 1019 Number Sequence

两道模板题 ...

POJ 2406 Power Strings

求最短的循环节的循环次数

上面已经说过了,直接 len / (len - f[len]) 用这个公式就行

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAXN 1000005

char str[MAXN] ;
int f[MAXN] ;

void get_nex( char * str ) {
	int len = strlen( str ) ;
	int j;
	f[0] = f[1] = 0 ;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

int main(){
	while( scanf( "%s" , str ) != EOF ) {
		if( strcmp( "." , str ) == 0 ) break;
		get_nex( str ) ;
		int len = strlen( str ) ;
		if( len % ( len - f[len] ) == 0 ) {
			printf( "%d\n" , len / ( len - f[len] ) ) ;
		}else{
			printf( "1\n" ) ;
		}
	}
	return 0 ;
}

HDOJ 3336 Count the string

求各个前缀在字符串中出现的次数的总和

dp[i] 表示 以字符i-1为结尾的和前缀相同的子串的有多少

那么 : dp[i] = dp[f[i]] + 1 , 首先以为结尾的字符串本身肯定是一个前缀,所以至少是1

然后dp[f[i]] 是以 f[i] -1 为结尾的前缀数 , 而s[0~f[i]-1]又刚好就是s[0~i-1]的后缀,所以第i-1个字符结尾的长度小于i的字符串总数为dp[f[i]]

最后求个和就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define mod 10007

char str[200005] ;
int    f[200005] ;
int   dp[200005] ;

void get_nex( char * str , int len ){
	f[0] = f[1] = 0 ;
	int j ;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

int main(){
	int cas ;
	scanf( "%d" , &cas ) ;
	while( cas -- ) {
		int len ;
		scanf( "%d" , &len ) ;
		scanf( "%s" , str ) ;
		get_nex( str , len );
		dp[1] = 1 ;
		int sum = 1 ;
		for( int i = 2 ; i <= len ; i ++ ) {
			dp[i] = dp[f[i]] + 1 ;
			sum += dp[i] ;
			sum %= mod ;
		}
		printf( "%d\n" , sum ) ;
	}
	return 0 ;
}

HDOJ 3336 Theme Section

求既是字符串的前缀,又是字符串的后缀,又在中间出现的最长子串( 三个不能重叠 ) 。

首先我们要求出所有既是前缀又是后缀的字符串的长度,用vis数组标记下

然后枚举中间的字符串的终点,求出 f[i] 在判断下合不合法 ,有没有标记过

最后求出长度最大,既合法,又被vis数组标记过的长度就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define MAXN 1000005

char str[MAXN] ;
int  f[MAXN] ;
bool vis[MAXN] ;

void get_nex( char * str , int len ) {
	f[0] = f[1] = 0 ;
	int j ;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = j ;
	}
}

int main(){
	int cas ;
	scanf( "%d" , &cas ) ;
	while( cas -- ) {
		scanf( "%s" , str ) ;
		int len = strlen( str ) ;
		memset( vis , false , sizeof(vis) ) ;
		get_nex( str , len ) ;
		int Len = f[len] ;
		while( Len ) {
			vis[Len] = true ;
			Len = f[Len] ;
		}
		int ans = 0 ;
		for( int i = 2 ; i < len ; i ++ ) {
			int ll = f[i] ;
			int tmp = min( min( ll , i / 2 ) , min( f[len] , len - i ) ) ;
			if( vis[tmp] ) ans = max( ans , tmp ) ;
		}
		printf( "%d\n" , ans ) ;
	}
	return 0 ;
}

POJ 2185 Milking Grid

就是求二维情况的循环串

我是先把一维用多项式hash压缩掉,求一维的循环节 , 然后在压缩另外一维 , 再求一遍就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;

#define MAXN 10005
char mp[MAXN][85] ;
typedef unsigned __int64 uLL ;
uLL a[MAXN] ;
int f[MAXN] ;

void get_nex( uLL * a , int len ){
	f[0] = 0 , f[1] = 0 ;
	int j ;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && a[i] != a[j] ) j = f[j] ;
		if( a[i] == a[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

int main(){
	int n , m ;
	while( scanf( "%d%d" , &n,  &m ) != EOF ) {
		for( int i = 0 ; i < n ; i ++ ) {
			scanf( "%s" , mp[i] ) ;
			a[i] = 0 ;
			for( int j = 0 ; j < m ; j ++ ) {
				a[i] = a[i] * 10007 + mp[i][j] - 'A' ;
			}
		}
		get_nex( a , n ) ;
		int H = n - f[n] ;
		for( int i = 0 ; i < m ; i ++ ) {
			a[i] = 0 ;
			for( int j = 0 ; j < H ; j ++ ) {
				a[i] = a[i] * 10007 + mp[j][i] - 'A' ;
			}
		}
		get_nex( a , m ) ;
		int W = m - f[m] ;
		printf( "%d\n" , H * W ) ;
	}
	return 0 ;
}

HDOJ 2594 Simpsons’ Hidden Talents

给你两个串, 让你求第一串和第二个串的最长公共前后缀

我直接把两个字符串用#连起来,求下失配函数, f[len]就是要求的答案了

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define MAXN 50005 * 2
char str[MAXN] ;
int f[MAXN] ;

void get_nex( char * str , int len ){
	f[0] = f[1] = 0 ;
	int j ;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

int main(){
	while( scanf( "%s" , str ) != EOF ) {
		int len = strlen( str ) ;
		str[len] = '#' ;
		scanf( "%s" , str + len + 1 ) ;
		len = strlen( str ) ;
		get_nex( str , len ) ;
		if( f[len] ) {
			str[f[len]] = 0 ;
			printf( "%s %d\n" , str , f[len] ) ;
		}else{
			printf( "0\n" ) ;
		}
	}
	return 0 ;
}

HDOJ 3746 Cyclic Nacklace

问至少增加一个字符可以变成至少有两个以上循环节的循环串

如果本身就是循环串 ,如果只有一个循环节,那要在复制一次字符串 , 否则答案就是0

不是的话,就看 len - f[len] 的长度 ,看添加几个能补到被len整数就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
using namespace std;

#define MAXN 400005

char str[MAXN] ;
int f[MAXN] ;

void get_nex( char * str , int len ){
	f[1] = f[0] = 0 ;
	int j;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

int main(){
	while( scanf( "%s" , str ) != EOF ) {
		int len = strlen( str ) ;
		get_nex( str , len ) ;
		stack<int> s ;
		s.push( len ) ;
		while( f[len] ) {
			s.push( f[len] ) ;
			len = f[len] ;
		}
		bool first = true ;
		while( !s.empty() ) {
			printf( first?"%d" :" %d" , s.top() ) ;
			s.pop() ;
			first = false ;
		}
		puts( "" ) ;
	}
	return 0 ;
}

POJ
2752 Seek the Name, Seek the Fame

就是求所有的前后缀的长度,从小到大输出来

上面已经讲过了
, 直接 len , f[len] , f[f[len]] ... 一路到0就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
using namespace std;

#define MAXN 400005

char str[MAXN] ;
int f[MAXN] ;

void get_nex( char * str , int len ){
	f[1] = f[0] = 0 ;
	int j;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

int main(){
	while( scanf( "%s" , str ) != EOF ) {
		int len = strlen( str ) ;
		get_nex( str , len ) ;
		stack<int> s ;
		s.push( len ) ;
		while( f[len] ) {
			s.push( f[len] ) ;
			len = f[len] ;
		}
		bool first = true ;
		while( !s.empty() ) {
			printf( first?"%d" :" %d" , s.top() ) ;
			s.pop() ;
			first = false ;
		}
		puts( "" ) ;
	}
	return 0 ;
}

ZOJ 3587 Marlon‘s String

给你两个字符串, 第一个字符串中取出两段来,有多少种方式可以组成第二个字符串。取出来的两段可以重叠

那么我们先统计一下cnt1[i] 表示第一个字符串中有多少子串是第二个字符长度为i的子串

计算的时候我们先根据匹配结果去统计,即到匹配到一次长度为i的就cnt1[i] ++ ; 然后因为s[0...i-1]
出现一次的话,那么s[0...f[i]-1]肯定也要出现一次,所以我们统计到cnt1[i] 的时候,要cnt1[f[i]] += cnt1[i]

当然出现一次 s[0...i-1]更短的也会出现过,但是我们计算到cnt1[i]的时候并不用统计,因为这些会在cnt1[f[i]]统计的时候加上

然后两个字符串反过来在匹配一遍,统计出cnt2[i]

那么最后答案就是Σ( cnt1[i] * cnt2[len-i] ) 了

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define MAXN 100001

typedef long long LL ;

char s[MAXN] ;
char t[MAXN] ;
char tmp[MAXN] ;
int cnt1[MAXN] , cnt2[MAXN] ;
int f[MAXN] ;

void get_nex( char * str , int len ) {
	f[0] = f[1] = 0 ;
	int j ;
	for( int i = 1 ; i < len ; i ++ ) {
		j = f[i] ;
		while( j && str[i] != str[j] ) j = f[j] ;
		if( str[i] == str[j] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

void KMP( char * str1 , int len1 , char * str2 , int len2 , int * cnt ) {
	int j = 0 ;
	for( int i = 0 ; i < len1 ; i ++ ) {
		while( j && str1[i]!=str2[j] ) j = f[j] ;
		if( str1[i] == str2[j] ) {
			j ++ ; cnt[j] ++ ;
		}
		if( j == len2 ) j = f[j] ;
	}
}

void stringrev( char * s ) {
	int len = strlen( s ) ;
	strcpy( tmp , s ) ;
	for( int i = 0 ; i < len ; i ++ ) {
		s[len-i-1] = tmp[i] ;
	}
	s[len] = 0 ;
}

int main(){
	int cas ;
	scanf( "%d" , &cas ) ;getchar() ;
	while( cas -- ) {
		gets(s);
		gets(t);
		int len1 , len2 ;
		len1 = strlen( s ) , len2 = strlen( t ) ;
		get_nex( t , len2 ) ;
		memset( cnt1 , 0 ,sizeof(cnt1) ) ;
		KMP( s , len1 , t , len2 , cnt1 ) ;
		for( int i = len2 ; i >= 1 ; i -- ) {
			cnt1[f[i]] += cnt1[i] ;
		}
		stringrev( s ) ;
		stringrev( t ) ;
		get_nex( t , len2 ) ;
		memset( cnt2 , 0 , sizeof(cnt2) ) ;
		KMP( s , len1 , t , len2 , cnt2 ) ;
		for( int i = len2 ; i >= 1 ; i -- ) {
			cnt2[f[i]] += cnt2[i] ;
		}
		LL ans = 0 ;
		for( int i = 1 ; i < len2 ; i ++ ) {
			ans += (LL)cnt1[i] * cnt2[len2-i] ;
		}
		printf( "%lld\n" , ans ) ;
	}
	return 0 ;
}

POJ 3167 Cow Patterns

给你两个序列 ,要求匹配模式串 ,怎么算匹配上呢 , 就是两个区间中各个数的相对名次是一样的

比如a[i]的名次比哪些小,和哪些一样,都要匹配上

我们预处理出每个数前面有几个比它小的和几个小于等于它的,然后改写下字符匹配上的标准就行了

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;

int n , m , s ;
int a[100005] , b[100005] ;
int sa[100005][30] ;
int sb[100005][30] ;
int f[100005] ;

vector<int> ans ;

void get_nex( int * a , int (*p)[30] , int len ){
	f[0] = f[1] = 0 ;
	int j ;
	for( int i = 1 ; i < len ; i++ ) {
		j = f[i] ;
		while( j && ( p[j+1][a[j]] != p[i+1][a[i]] - p[i-j][a[i]] || p[j+1][a[j]-1] != p[i+1][a[i]-1] - p[i-j][a[i]-1] ) ) j = f[j] ;
		if( p[j+1][a[j]] == p[i+1][a[i]] - p[i-j][a[i]] && p[j+1][a[j]-1] == p[i+1][a[i]-1] - p[i-j][a[i]-1] ) f[i+1] = j + 1 ;
		else f[i+1] = 0 ;
	}
}

void KMP( int * a , int (*p)[30] , int len1 , int *b , int (*q)[30] , int len2 ) {
	int j = 0 ;
	for( int i = 0 ; i < len2 ; i ++ ) {
		while( j && ( p[j+1][a[j]] != q[i+1][b[i]] - q[i-j][b[i]] || p[j+1][a[j]-1] != q[i+1][b[i]-1] - q[i-j][b[i]-1] ) ) j = f[j] ;
		if( p[j+1][a[j]] == q[i+1][b[i]] - q[i-j][b[i]] && p[j+1][a[j]-1] == q[i+1][b[i]-1] - q[i-j][b[i]-1] ) j ++ ;
		if( j == len1 ) ans.push_back( i - len1 + 2 ) , j = f[j] ;
	}
}

int main(){
	while( scanf( "%d%d%d" , &n , &m , &s ) != EOF ) {
		for( int i = 0 ; i < n ; i ++ ) {
			scanf( "%d" , &a[i] ) ;
			sa[i+1][a[i]] ++ ;
			for( int j = 1 ; j <= s ; j ++ )
				sa[i+1][j] += sa[i][j] ;
		}
		for( int i = 0 ; i < n ; i ++ ) {
			for( int j = 1 ; j <= s ; j ++ )
				sa[i+1][j] += sa[i+1][j-1] ;
		}
		for( int i = 0 ; i < m ; i ++ ) {
			scanf( "%d" , &b[i] ) ;
			sb[i+1][b[i]] ++ ;
			for( int j = 1 ; j <= s ; j ++ )
				sb[i+1][j] += sb[i][j] ;
		}
		for( int i = 0 ; i < m ; i ++ ) {
			for( int j = 1 ; j <= s ; j ++ )
				sb[i+1][j] += sb[i+1][j-1] ;
		}
		get_nex( b , sb , m ) ;
		ans.clear() ;
		KMP( b , sb , m , a , sa , n ) ;
		printf( "%d\n" , ans.size() ) ;
		for( int i = 0 ; i < ans.size() ; i ++ ) {
			printf( "%d\n" , ans[i] ) ;
		}
	}
	return 0 ;
}

KMP专题总结,布布扣,bubuko.com

时间: 2024-08-03 15:30:41

KMP专题总结的相关文章

KMP专题

1.HDU 1711 Number Sequence 题意:给出两个数字串a,b,问能否使得数字串b为a的子串,能输出最小的匹配位置. 思路:KMP模板题 1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn = 1000010; 5 const int maxm = 10010; 6 int p[maxm]; 7 int des[maxn]; 8 int Next[maxm

2017-4-13:KMP专题

G - 剪花布条(KMP) 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input 输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样.花纹条和小饰条不会超过1000个字符长.如果遇见#字符,则不再进行工作. Output 输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果

hdu---2087---剪花布条

hdu2087剪花布条字符串的处理 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 这题水的不要不要的,各种数据都能过,醉醉的 写他的目的是在KMP专题上随时都要充实自己,又长知识了. kmp算法完成的任务是:给定两个字符串O和f,长度分别为n和m,判断f是否在O中出现,如果出现则返回出现的位置. 常规方法是遍历a的每一个位置,然后从该位置开始和b进行匹配,但是这种方法的 复杂度是O(nm).kmp算法通过一个O(m)的预处理,使匹配的复杂

大一下学期以来做题总结、

这段时间以来.除了搜索专题和KMP专题 其他专题都不怎么愿意想了. 就比如今天的水题. 代码敲错. 输出格式没看清题意. 看题又不仔细. 等交上去错一发之后在回过头来看题目. 而且看题这方面真的好差. 经常性题目没读完就开始去敲代码.在敲代码过程中再去看题意. 希望自己读题的时候要认真.争取把题目读准.读快. 还有一个坏习惯.做题的时候喜欢听歌.这样在做思维题的时候多少会有点影响把. 这样好了,以后在做题时间一定一定不要听歌. 还有就是思维方面比以前欠缺一点了. 可能是因为没有比赛时的感觉的了.

E - Period HDU-1358

题目大意: 多组.给一个n,输入长度为n 的串,求:这个串所有存在循环节的前缀,输出前缀长度和循环次数(不重叠). 解题思路: 从i=0开始,判断前缀是不是存在循环节,即(i+1)%(i-next[i]) 是否==0 .注:next[i]值是0或-1的忽略,说明前面不存在任何循环节.(关于循环节解释的见<KMP 专题知识>). 参考代码: 1 #include <iostream> 2 #include <stdio.h> 3 using namespace std;

D - Cyclic Nacklace HDU-3746

题目大意: 给一个t,接下来每个t,给一个串,求出最小循环节下还要增加多少个珠子才完美.(要是都没啥循环节,就输出长度) 解题思路: 求出最小循环节 cir:cir=len - next[len] (关于为什么是这个式子详见<KMP 专题知识>),然后拿len%cir得到的余数就是已经有的,那么拿循环节再减掉有的,就是需要增加的.即:cir-len%cir.如果len%cir == 0,而且cir!=len,就意味着一颗都不用增加,因为此时已经是完美的循环了,但是要是cir==len,就说明没

(字典树)How many--hdu--2609

http://acm.hdu.edu.cn/showproblem.php?pid=2609 How many Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1707    Accepted Submission(s): 693 Problem Description Give you n ( n < 10000) necklaces

KMP &amp; 扩展KMP &amp; Manacher 专题

KMP & 扩展KMP & Manacher  专题 先来模版: void getNext(int *b,int m) { Next[0]=-1; int i=0,j=-1; while(i<m&&j<m){ if(j==-1||b[i]==b[j]) Next[++i]=++j; else j=Next[j]; } } int kmp(int *a,int *b,int n,int m) { getNext(b,m); int i=0,j=0; while(i

·专题」 KMP

KMP 总结 1.strstr函数 |函数名: strstr |功 能: 在串中查找指定字符串的第一次出现 |用 法: char *strstr(char *str1, char *str2); |据说strstr和KMP的算法效率差不多|注意:返回的是该字符串第一次出现时的指针,所以如果要计算下标,可以用原字符串首地址-返回的地址. 因为这样,还可以直接输出余下的字符串 1 int main() 2 { 3 char T[] = {"I love you ,do you know?"