KMP演算法next陣列活用之前後綴問題
前置技能 KMP字串匹配演算法: KMP字串匹配演算法
正如題目中描述:
你的任務是找出一個字串s,s既是String的字首,又是String的字尾,並且s也出現在String的中間部分(既不是字首,也不是字尾),s的長度越長越好。
很明顯這是一道KMP演算法周邊題目,說是KMP演算法是因為需要計算next陣列,說是周邊是因為這並不是一道匹配型別的題目。
正如《KMP字串匹配演算法》所說,next陣列的目的是儲存的匹配過的 S 串中還有多少直接等於 T 串的。但實際上,next中的數值的含義在不同的使用場景還有很多種理解。
比如求前後綴的題目中,我們就可以把next中的陣列看做在next[i](next[i]!=0 and next[i] != -1)出,存在重複的欄位String[0,next[i]]。
而對於這個題目,對於長度為len-1的字串,那麼next陣列的長度為len。
如果在next陣列中,如果next[len]為0,這可以說明不存在後綴和字首相同的情況。如果next[len]不為0,這說明字首和字尾相同,但是還不能說明中間存在這一迴圈體。
如果next[len]不為0,而且存在和next[len]一樣的值,也就是說在在字串中間出現了迴圈題,也就可以斷定存在符合題目要求的字串,而長度就是next[len](也就是字尾和字首共同的長度)。
但如果串是一個迴圈串,比如像"papapapa"這種,那麼next是遞增的。因此不能用上段的方式判斷十分滿足題目要求。
因此需要判斷出去最短迴圈節之後時候還是迴圈串。而除去最短迴圈串,便是String[0,next[len]]。因此,在該串的基礎上進行判斷,也就是判斷next[next[i]]十分還是一個有效的值(非0和非-1),如果有效,說明依然存在欄位重複。
因此這個題目就非常清楚了:只需要尋找next[i] == next[len]和判斷 next[next[len]] != 0 且 next[next[len]] != -1。
把KMP相關演算法封裝,這個題目的核心程式碼就變成了:
/** * SDUTOJ 2748 * Created by hypo on 15-11-15. */ class TestString{ private String str; private int[] next; //初始化 順便獲得next陣列 public TestString(String str) { this.str = str; next = getNext(); } //獲取next陣列 private int[] getNext(){ char[] chars = this.str.toCharArray(); int len = chars.length; int[] next = new int[len + 1]; int k = -1, i = 0; next[0] = -1; while(i < len){ if(k == -1 || chars[k] == chars[i]){ i++; k++; next[i] = k; }else{ k = next[k]; } } return next; } //獲得結果 null表示不符合題目要求 public String getAns(){ int len = this.str.length(); if(next[len] == 0){ return null; } for(int i = 0;i < len;i++){ if(this.next[i] == next[len]){ return this.str.substring(0,next[len]); } } if (next[next[len]] != 0 && next[next[len]] != -1) { return this.str.substring(0,next[next[len]]); } return null; } }
歡迎到微信裡去當吃瓜群眾