KMP算法详解及时间复杂度分析

KMP算法用于判断一个字符是否是另一个字符的子串

概念:字符串中 一个字符前面的字符串 的前缀与后缀的最长匹配长度(短的那个字符串)

注意:前缀与后缀不可以是整个子字符串

例如:a b c a b c d , d位置的最长匹配长度为3,abc 与 abc 匹配


Next数组:长度与字符串长度一致,每个位置存储对应字符的最长匹配长度

Next数组求解:

1.初始位置,由于第一个字符前面没有字符规定, Next[0] = -1; 由于第二个字符前面只有一个字符,Next[1] = 0.

2.后续位置,使用数学归纳法,根据前面已经求过的数组值来求取Next[i];

设字符串为str:

如果str[i] == str[x1] , Next[i + 1] = Next[i] + 1;

否则把str[i]与str[x2]比较,如果相等,Next[i + 1] = Next[x1] + 1;

直到走到字符串的第一个位置,求取Next数组的代码如下

vector<int> getNextArray(string str) {
	if (str.size() == 1) {
		vector<int> Next(1, -1);
		return Next;
	}
	vector<int> Next(5);
	Next[0] = -1;
	Next[1] = 0;
	int i = 2;//Next数组中待求的位置
	int cm = 0;//与str[i - 1]比较的位置
	while (i < str.size()) {
		if (str[i - 1] == str[cm]) {
			Next[i++] = ++cm;//cm的值一直保持和Next[i - 1]一样
		}
		else if (cm > 0)
		{
			cm = Next[cm];
		}
		else
		{
			Next[i++] = 0;//str[i - 1] != str[0]
		}
	}
	return Next;
}

2.KMP算法的比较过程

X与Y位置不匹配,根据X位置的匹配串长度,可以把圆圈位置的字符直接与Y比较,完成加速过程

int getIndexOf(string str1, string str2) {
	vector<int> Next = getNextArray(str2);
	int i1 = 0;
	int i2 = 0;
	while (i1 < str1.size() && i2 < str2.size()) {
		if (str1[i1] == str2[i2]) {
			i1++;
			i2++;
		}
		else if (i2 != 0) {
			i2 = Next[i2];
		}
		else{
			i1++;//一直后退到str2[0]都不相等,只有i1向前走一个
		}
	}
	return i2 == str2.size() ? i1 - i2 : -1;//i2 == str2.size()代表str2走完了
}

 主函数如下:

int main()
{
	string match = "ababa";
	string str = "abcabcababaccc";
	cout << getIndexOf(str, match);
	return 0;
}

时间复杂度分析

设str1长度为n, str2的长度为m,

Next数组的求取:为O(m)

总的时间复杂度为:O(n)

猜你喜欢

转载自blog.csdn.net/qianji_little_boy/article/details/83448827