KMP算法解决字符串匹配问题

        KMP算法解决的问题是字符匹配,是由Knuth–Morris–Pratt共同开发出来的,这个算法把字符匹配的时间复杂度缩小到Om+n,而空间复杂度也只有O(m),ntarget的长度,mpattern的长度,在此算法在发明之前并不是没有如此高效的算法,但是原算法比较复杂。Kmp算法优雅高效,但是实现却不难理解且代码长度很短,是优秀算法设计的典范,值得拿出来仔细分析。

一、原始匹配算法

 先来看一个比较原始的匹配算法,对于目的字串targetbanananobano,要匹配的字串patternnano,的情况,下面是匹配过程,原理很简单,只要先和target字串的第一个字符比较,如果相同就比较下一个,如果不同就把pattern右移一下,之后再从pattern的每一个字符比较,这个算法的运行过程如下图,index表示的每n次匹配的情形,这种匹配的代码也比较容易写,如下面:

《KMP算法解决字符串匹配问题》

 

#include<iostream>
#include<string>
using namespace std;

int match(const string &target,const string &pattern)
{
	int target_length=target.size();
	int pattern_length=pattern.size();
	int target_index=0;
	int pattern_index=0;
	while((pattern_index !=pattern_length) && (target_index!=target_length))
	{
		if(target[target_index]==pattern[pattern_index])
		{
			++target_index;
			++pattern_index;
		}
		else
		{
			target_index=target_index-pattern_index+1;
			pattern_index=0;
		}
	}
	if(pattern_index==pattern_length)
	{
		return target_index-pattern_length;
	}
	else
	{
		return -1;
	}
}

int main(int argc, char* argv[])      
{
	cout<<match("banananobano","nano")<<endl;
	return 0;
}         

上面的算法进间复杂度是O(pattern_length*target_length),我们主要把时间浪费在什么地方呢,观查index =2那一步,我们已经匹配了3个字符,而第4个字符是不匹配的,这时我们已经匹配的字符序列是nan,此时如果向右移动一位,那么nan最先匹配的字符序列将是an,这肯定是不能匹配的,之后再右移一位,匹配的是nan最先匹配的序列是n,这是可以匹配的,如果我们事先知道pattern本身的这些信息就不用每次匹配失败后都把target_index回退回去,这种回退就浪费了很多不必要的时间,如果能事先计算出pattern本身的这些性质,那么就可以在失配时直接把pattern移动到下一个可能的位置,把其中根本不可能匹配的过程省略掉,如上表所示我们在index=2时失配,此时就可以直接把pattern移动到index=4的状态,kmp算法就是从此出发。

二、kmp算法

1. 覆盖函数(overlay_function)

覆盖函数所表征的是pattern本身的性质,可以让为其表征的是pattern从左开始的所有连续子串的自我覆盖程度。

比如如下的字串,abaabcaba


    原文作者:KMP算法
    原文地址: https://blog.csdn.net/yuanyuanprince/article/details/7585993
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞