BF到KMP,再到后缀数组的字符串匹配

总结了下,关于BF算法,以及KMP。遇到后缀数组的时候突然发现,KMP还是有用的啊~~~后缀数组更简单,就是代码比较长~~

/*
记住一个公式:KMP算法=BF算法+next数组 

->1.BF算法中,只需要将j=next[j],避免回溯就行了。所以计算 next数组
->2.计算next数组
做两个变量j,k
j=0(用于记录计算P串的位置,j=0~(n-1),最有一个不用计算)
k=-1(记录k在P串位置的前后串最长公共前后缀)

******理解下:0~k~(n-1)分k左右一个串,左右串中存在k之前的串与,
后面j(j一般在k~n之间)之前的串相等。然后看next函数里面的递推关系就比较容易理解了 ,简单吧,书上讲解的太蛋碎了~~ 

adsadjkhasdadabcabdabcabcaaasdasda
abcabdabcabcaa

13
*/
#include<iostream>
using namespace std;
const int MAXN=1<<7;
char T[MAXN],P[MAXN],next[MAXN];;
int N;
void input(){
	scanf("%s",T);
	scanf("%s",P);
}
/*
ababdabcd
abc
*/
int BF(){
	int n=strlen(T),m=strlen(P);
	int i=0,j=0;
	while(i<n){
		if(T[i]==P[j]){
			i++;
			j++;
		}else{
			i=i-j+1;
			j=0;//j=next[j];就是KMP算法了。next数组避免了j=0的回溯!!!!!!!
		}
		if(j==m) return i-j;
	}
	return -1;
}
/*
由BF改进过来的KMP
*/
int KMP(){
	int n=strlen(T),m=strlen(P);
	int i=0,j=0;
	while(i<n){
		if(T[i]==P[j]){
			i++;
			j++;
		}else{
			i=i-j+1;
			j=next[j];
		}
		if(j==m) return i-j;
	}
	return -1;
}

int getNext(){
	int n=strlen(P);
	next[0]=-1;
	int j=0,k=-1;
	while(j<(n-1)){
		if(k==-1 || P[j]==P[k]){
		j++;
		k++;
		next[j]=k;
		/*
		//将next[j]=k;替换成下面的代码,避免了next中k的回溯
		if(P[j]!=P[k]){
		next[j]=k;
		}else
		next[j]=next[k];
		*/
		}else{
			k=next[k];
		}
	}
	return *next;  //其实可以返回void类型的,但是就是想测试下如何返回数组来着。这个多余了。
}

int main(){
	input();
	printf("BF:%d\n",BF());
 	getNext();
   	int i=0,n=strlen(P);
	while(i<n) printf("%d ",next[i++]);
	printf("\n");
	printf("KMP:%d\n",KMP());
	return 0;
}

KMP瞬间简单了吧~~~~看书会死人的~~

时间: 2024-10-15 20:58:40

BF到KMP,再到后缀数组的字符串匹配的相关文章

POJ2406 Power Strings(KMP,后缀数组)

这题可以用后缀数组,KMP方法做 后缀数组做法开始想不出来,看的题解,方法是枚举串长len的约数k,看lcp(suffix(0), suffix(k))的长度是否为n- k ,若为真则len / k即为结果. 若lcp(suffix(0), suffix(k))的长度为n- k,则将串每k位分成一段,则第1段与第2段可匹配,又可推得第2段与第3段可匹配……一直递归下去,可知每k位都是相同的,画图可看出匹配过程类似于蛇形. 用倍增算法超时,用dc3算法2.5秒勉强过. #include<cstdi

后缀数组 &amp; 题目

后缀数组被称为字符串处理神器,要解决字符串问题,一定要掌握它.(我这里的下标全部都是从1开始) 首先后缀数组要处理出两个数组,一个是sa[],sa[i]表示排名第i为的后缀的起始位置是什么,rank[i]表示第i个字符为起始点的后缀,它的排名是什么.可以知道sa[rank[i]] = i; rank[sa[i]] = i; 由于每个后缀各不相同,至起码长度不同,所以每个后缀是不可能相等的. 解除一个值,就能在O(n)时间内得到另外一个. 定义:suffix(i)表示从[i, lenstr]这个后

【转】后缀数组解题总结

之前觉得后缀自动机会了,就忽略了后缀数组,现在发现后缀数组+二分的功能很强,而且后缀自动机好像实现不了. 转发一下,方便队友大概看一下.这几天我也尽快恶补一下. (找不到原博主网站了,失误) 后缀数组解题总结: 1.求单个子串的不重复子串个数.SPOJ 694.SPOJ 705. 这个问题是一个特殊求值问题.要认识到这样一个事实:一个字符串中的所有子串都必然是它的后缀的前缀.(这句话稍微有点绕...)对于每一个sa[i]后缀,它的起始位置sa[i],那么它最多能得到该后缀长度个子串(n-sa[i

后缀数组专题

后缀数组基本模板 ①倍增法(时间O(NlogN),空间O(N)) 1 #include<iostream> 2 using namespace std; 3 const int maxl = 100010; 4 char s[maxl]; 5 int totlen; 6 int r2[maxl], cc[maxl],SA[maxl], RANK[maxl], Height[maxl]; 7 //r2:以第二关键字对后缀排序所得的辅助数组 8 //cc:计数排序辅助数组 9 //RANK:RAN

hdu1403(后缀数组模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意: 给出两个字符串, 求他们的最长公共子串 思路: 两个字符串的最长公共子串长度显然就是两个字符串的所有后缀中的最长公共前缀长度. 可以先用一个没有出现的字符(便于后面区分后缀是否属于相同字符串)将两个字符串连成一个字符串,再用后缀数组求其height, SA数组, 对于当前 i, 通过 SA 数组区分后缀 i 和 i - 1 是否在同一个初始字符串中, 若不是则用 height[i] 维

字符串匹配:从后缀自动机到KMP

后缀自动机(sam)上的字符串匹配 ==== 我们把相对较短的模式串构造成sam. 对于P="abcabcacab", T[1..i]的后缀,使得它是sam的最长前缀长度: T: b a b c b a b c a b c a a b c a b c a b c a c a b  c 1 1 2 3 1 1 2 3 4 5 6 7 1 2 3 4 5 6 7 5 6 7 8 9 10 4 如果最长前缀长度是|P|,则表示T[1..i]的后缀和P匹配. 内存使用 可能多个trans指针同

[luoguP2870] [USACO07DEC]最佳牛线,黄金Best Cow Line, Gold(后缀数组)

传送门 数据小的话贪心就行. 可以把这个串翻转再接到后面,再求后缀数组,求出 rank 数组就很简单了. ——代码 1 #include <cstdio> 2 #include <iostream> 3 #define N 60001 4 5 int n, len, m = 256, sum; 6 int buc[N], x[N], y[N], sa[N], rank[N]; 7 char s[N]; 8 9 inline void build_sa() 10 { 11 int i

后缀数组小结

后缀数组又被称为字符串处理神器: http://blog.csdn.net/xymscau/article/details/8798046 这里讲的非常好 实现rank排名是用到了倍增法和一个比较神奇的计数排序,时间复杂度是nlongn height[i]存放的是排名第i的后缀与排名第i-1的后缀的最长前缀, sa[i]存的是排名第i的后缀是第几位开头的 rk[i]存放第i个位置开头的后缀的字典序排名 1.poj2774(后缀数组水题) 题意:给你两串字符,要你找出在这两串字符中都出现过的最长子

POJ 2774 Long Long Message(最长公共子串 -初学后缀数组)

后缀数组的两篇神论文: 国家集训队2004论文集 许智磊 算法合集之<后缀数组--处理字符串的有力工具> 很多人的模版都是用论文上的 包括kuangbin的模版:(DA算法) 模版中比较难理解的地方有两点1.按关键词排序 2.把字符串长度增加一位 按关键词排序的意思其实是基数排序中相当把两位数排序时先排个位,再排十位 这里也一样先排后2^k长度的字符串,再排前2^k长度的字符串,最终排成2^(k+1)字符长度的后缀数组sa 把字符串增加一位,是为了让有意义的串的rank从1开始,还有便于后边不