《算法笔记》读书记录DAY_62

CHAPTER_12  提高篇(6)——字符串专题

12.2.1 字符串匹配问题

本节主要讨论字符串匹配的问题,如果给出两个字符串text和pattern,需要判断pattern是否为text的子串。一般把text称作文本串,把pattern称作模式串。

字符串匹配的暴力解法很容易想到,只需要枚举文本串的起始位置 i ,然后从该位开始逐位与模式串进行匹配,如果匹配过程中每一位都相同,则匹配成功;否则,只要出现某位不同,就让文本串的起始位置变为 i+1,并从头开始模式串的匹配。这种做法时间复杂度位O(mn),其中m和n为模式串和文本串的长度。对于一些长字符串,这个时间复杂度让人无法接受。

我们有更优秀的KMP算法来解决字符串匹配问题,时间复杂度为O(m+n)。

12.2.2 next数组

在正式进入KMP算法之前,先要学习一个重要数组。假设有一个字符串s(下标从0开始),那么它以 i 号位作为结尾的子串就是s[0...i]。对该子串来说,长度为k+1的前缀和后缀分别是s[0...k]与s[i-k...i]。现在定义一个int型数组next,其中next[i]表示使子串s[0...i]的前缀s[0...k]的前缀等于后缀s[i-k...i]的最大的k(注意前缀和后缀可以部分重叠,但不能是s[0...i]本身);如果找不到相等的前后缀,那么就令next[i]=-1。显然,next[i]就是所求最长相等前后缀中前缀最后一位的下标。

以字符串"ababaab"作为举例,next数组的计算过程如下图:

那么。如何求解next数组呢?我们采用递推的方法求解,即假设已经求出了next[0]~next[i-1],现在要求next[i]。

以"abababc"为例子,《算法笔记》中将next数组的求解过程清晰地阐述如下:

  

看懂了next数组的求解过程,我们总结出逻辑:

(1)初始化next数组,令j=next[0]=-1。

(2)让 i 在1~len-1的范围内遍历,对每个 i ,执行(3)(4)。

(3)不断令j=next[j],直到 j 回退至-1,或是s[i]==s[j+1]成立。

(4)如果s[i]==s[j+1],next[i]=j+1;否则next[i]=j。 

//求解长度为len的字符串s的next数组
void getNext(char s[],int len) {
	int j=-1;
	next[0]=-1;
	for(int i=1;i<len;i++) {
		while(j!=-1&&s[i]!=s[j+1]) {
			j=next[j];
		}
		if(s[i]==s[j+1]) {
			j++;
		}
		next[i]=j;
	}
} 

猜你喜欢

转载自blog.csdn.net/jgsecurity/article/details/121429854