码迷,mamicode.com
首页 > 编程语言 > 详细

[hiho 03]KMP算法

时间:2015-04-21 20:35:55      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:

题目描述

暴力解法:枚举原串起始位置,逐个匹配,复杂度O(mn)。

优化思路:失配时,前面已匹配的字符可以提供信息。

 

KMP算法:

对于模式串任意位置 i ,如果我们知道一个 k 使得 i 位置前的 k 个元素和模式串最开始的前 k 个元素一一相等,那么第 i 个元素失配时就可以之间从第 k + 1 个元素开始继续匹配,这就利用到了失配前的匹配信息。

于是我们想构造这样一个数组 next_val[]  使得 next_val[i] 指向第 i 元素失配时下一个匹配的位置。

例如对于模式串abcabd,它的 next_val[] 数组如下,其中 –1 表示第一个元素也无法匹配:

下标 0 1 2 3 4 5
字符 a b c a b d
next_val -1 0 0 0 1 2

其实这个数组还可以优化,就是要把失配提供的信息也利用上。

如果第 i 个元素已经失配,那么如果 next_val[i] 对应的元素与第 i 个元素相同,那么其实不用进行下一次比较,于是把 next_val[i] = next_val[next_val[i]]。

下面的问题就是如何求解 next_val 数组。

这是个比较简单的递推问题,即“如果已知 next_val[1,…,k-1],如何求 next_val[k]”?

结合 next_val 数组的定义和以下代码不难理解,重点是理解第6行。

void init_next() {
	int len = strlen(ptn);
	next_val[0] = -1;
	int i = 0, j = next_val[i];
	while (i < len) {
		if (j == -1 || ptn[i] == ptn[j]) {
			next_val[i + 1] = j + 1;
			if (j != -1) {
				next_val[i] = next_val[next_val[i]];
			}
			i++;
			j++;
		}
		else {
			j = next_val[j];
		}
	}
}

得到了 next_val 数组后,就逐个匹配,失配时模式串位置标记通过 next_val 数组跳就行了。

代码如下:

int kmp() {
	init_next();
	int ans = 0;
	int str_len = strlen(str);
	int ptn_len = strlen(ptn);
	int i = 0, j = 0;
	while (i < str_len) {
		if (j == -1 || str[i] == ptn[j]) {
			i++;
			j++;
		}
		else {
			j = next_val[j];
		}
		if (j == ptn_len) {
			ans++;
		}
	}
	return ans;
}

吐槽:KMP算法思想虽然简单,理解起来也不复杂,但是要讲清楚太难了,不懂的话其实可以结合例子理解一下 next_val 的求法。

[hiho 03]KMP算法

标签:

原文地址:http://www.cnblogs.com/xblade/p/4445177.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!