KMP算法中的next[]數組

KMP算法最難懂的就是next[]數組的求法。

用一個例子來解釋,下面是一個子串的next數組的值,可以看到這個子串的對稱程度很高,所以next值都比較大。

位置i

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

前綴next[i]

0

0

0

0

1

2

3

1

2

3

4

5

6

7

4

0

子串

a

g

c

t

a

g

c

a

g

c

t

a

g

c

t

g


申明一下:下面說的對稱不是中心對稱,而是中心字符塊對稱,比如不是abccba,而是abcabc這種對稱。


(1)逐個查找對稱串。
這個很簡單,我們只要循環遍歷這個子串,分別看前1個字符,前2個字符,3個... i個 最後到15個。


第1個a無對稱,所以對稱程度0


前兩個ag無對稱,所以也是0


依次類推前面0-4都一樣是0


前5個agcta,可以看到這個串有一個a相等,所以對稱程度爲1前6個agctag,看得到ag和ag對成,對稱程度爲2


這裏要注意了,想是這樣想,編程怎麼實現呢?


只要按照下面的規則:
a、當前面字符的前一個字符的對稱程度爲0的時候,只要將當前字符與子串第一個字符進行比較。這個很好理解啊,前面都是0,說明都不對稱了,如果多加了一個字符,要對稱的話最多是當前的和第一個對稱。比如agcta這個裏面t的是0,那麼後面的a的對稱程度只需要看它是不是等於第一個字符a了。


 


b、按照這個推理,我們就可以總結一個規律,不僅前面是0呀,如果前面一個字符的next值是1,那麼我們就把當前字符與子串第二個字符進行比較,因爲前面的是1,說明前面的字符已經和第一個相等了,如果這個又與第二個相等了,說明對稱程度就是2了。有兩個字符對稱了。比如上面agctag,倒數第二個a的next是1,說明它和第一個a對稱了,接着我們就把最後一個g與第二個g比較,又相等,自然對稱成都就累加了,就是2了。


 


c、按照上面的推理,如果一直相等,就一直累加,可以一直推啊,推到這裏應該一點難度都沒有吧,如果你覺得有難度說明我寫的太失敗了。


當然不可能會那麼順利讓我們一直對稱下去,如果遇到下一個不相等了,那麼說明不能繼承前面的對稱性了,這種情況只能說明沒有那麼多對稱了,但是不能說明一點對稱性都沒有,所以遇到這種情況就要重新來考慮,這個也是難點所在。
(2)回頭來找對稱性
這裏已經不能繼承前面了,但是還是找對稱成都嘛,最愚蠢的做法大不了寫一個子函數,查找這個字符串的最大對稱程度,怎麼寫方法很多吧,比如查找出所有的當前字符串,然後向前走,看是否一直相等,最後走到子串開頭,當然這個是最蠢的,我們一般看到的KMP都是優化過的,因爲這個串是有規律的。


在這裏依然用上面表中一段來舉個例子:   


位置i=0到14如下,我加的括號只是用來說明問題:


(a g c t a g c )( a g c t a g c) t


我們可以看到這段,最後這個t之前的對稱程度分別是:1,2,3,4,5,6,7,倒數第二個c往前看有7個字符對稱,所以對稱爲7。但是到最後這個t就沒有繼承前面的對稱程度next值,所以這個t的對稱性就要重新來求。


這裏首要要申明幾個事實
1、t 如果要存在對稱性,那麼對稱程度肯定比前面這個c 的對稱程度小,所以要找個更小的對稱,這個不用解釋了吧,如果大那麼t就繼承前面的對稱性了。


2、要找更小的對稱,必然在對稱內部還存在子對稱,而且這個t必須緊接着在子對稱之後。

附上代碼

#include<iostream>
#include<algorithm>
#include <vector>
#include<string.h>
#include<ctype.h>
#include<math.h>
using namespace std;
void fun();
int main()
{
	fun();
	return 0;
}
void fun()
{
	int i,j,nextarr[1000];
	char str1[1000];
	gets(str1);
	nextarr[0]=-1;
	j=-1;
	i=0;
	while(i < strlen(str1)-1)
	{
		if(j == -1 || str1[i] == str1[j])
		{

			i++;
			j++;
			nextarr[i] = j;
		}
		else
		{
			j = nextarr[j];
		}
	}
	for(i=1;i<strlen(str1);i++)
		cout<<nextarr[i]<<" ";
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章