您的位置:首页 > 其它

kmp 朴素和升级 附 hdu 1711 3746 思想

2012-08-14 15:33 211 查看
kmp啊啊啊啊啊 我势必要ko了你啊 啊啊

写给几天以后就可能把这个算法忘记的我。。。

以abcdabd为子串

next里共有len+1个数的 -1 0 0 0 0 1 2 0 最后一个0是对应最后一个d的 虽说字符匹配的时候用不上,但有的题是能用上的~!

比如说hdu 3746 后边再说

next数组是错位相存的 但是巧妙的对应上了 上详解代码

void getnext()

{

int i=0,j=-1;next[0]=-1;//这个next[0]就是个头,因为他占一位,所以往后的数存时都是往后串了一个,这样的好处是查询kmp时,当前位置所对应的next就是他的前一个的数的实质next,而这个next值对应的也就是前一个指向的后一个。(因为正常来说,当一个字符失配时,我们是找他前一个数的失配值所指向的字符的后一个字符,用这个字符再与刚才失配的那个进行匹配)

比如 a b c d a b d

next -1 0 0 0 0 1 2 0

我们找到第二个b时失配了,找他对应的next数组 是1 那我们就找到了第一个b(有点不完美,貌似非朴素版可以改进?待我过会看看)

又如我们找到了第二个d时,失配了。。他对应的next数组是2 那我们就找到了第一个c,用c来进行匹配。(正常来说,d失配 我们就应该找他前一个也就是b的失配字符(也就是第一个b)的后一个字符(也就是c)接着来进行匹配。)

while(i!=len)//这里还要说一下,i是相当于从头到尾不变的一个指针,j相当于来回跳的那个s[i]与前边第几个(第j个)字符相匹配的那个指针。

{

if(j==-1||s[i]==s[j])//j=-1时,代表跳到头了,也就是s[i]和这几个都匹配失败,所以下边++i。

next[++i]=++j;//这里很巧妙啊 就相当于next整体后串了一下,next值也+1了。

else

j=next[j];//j开始跳了。。往s[j]他的失配点跳

}

}

我们会发现,getnext实质就是自身的kmp匹配。next我们可以理解为dian这一点与前边多少个字符相匹配(当然是错位以后的next)。一定是与最前边的字符相匹配。

再来就是子串与母串相匹配了。

int kmp()

{

int i=0,j=0;//i是母串的指针,j是子串的指针,len1为母串长,len2为子串长。

while(i!=len1)

{

if(j==-1||S[i]==s[j])//j=-1,还是那个原理,都跳到头了,都没匹配上,i++吧

{

++i;++j;

if(j==len2) return i-j+1;//都匹配完了,成功了 返回吧

}

else

j=next[j];//看到了吧,直接找next就行了 用next指向的字符与失配点进行匹配

}

return -1;//全部匹配失败。。真悲剧

}

这就是 kmp思想了 主要就是先把自身处理一下,next记录跳转点,因为据我理解就是与前边的对应点,你既然记录了,肯定是你当前这点的前n个与一开始的前n个相对应上了已经,所以可以跳了。

我们在来说 hdu 的3746

就是讲 一个串循环 还差多少个

比如 aaa 就三个循环串 不差了 0个

basdg 这是一个循环串 所以还要补 5个

adcca adcc算一个循环串,然后后边有跟了一个a 所以还差3个

abcdabcdab abcd是一个循环串,然后ab,所以还差2个

你用next数组 next[len]存的就是最后这点与前边的第几个相对应。

比如说 abcdabcdab 那最后一个next[10]就是6 那么 len-next[10],就是循环串的长度。

再来说说升级版的kmp

这个版本的其实我觉得没什么用。。可能是我太弱了,看不出其中的奥妙。。因为我觉得他能实现的朴素都能实现,而朴素能做的他却做不了

void getnext()

{

int i=0,j=-1,len=strlen(s);

next[0]=-1;

while(i!=len)

{

if(j==-1||s[i]==s[j])

{

++i;++j;

if(s[i]!=s[j]) //重点在这 看看后一个相不相匹配 若不匹配,next[i]配上失配点

next[i]=j;

else

next[i]=next[j]; //若匹配,配上上一个失配点 next[j]里放的一定是他的失配点

}

else

j=next[j];

}

}

再来看看 kmp

int kmp()

{

int i=0,j=0,lens=strlen(s),lenT=strlen(T);

while(i!=lens&&j!=lenT)

{

if(s[i]==T[j])

{

++i;++j;

}

else

{

if(next[j]==-1)

{

++i;j=0;

}

else

j=next[j];

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: