1. 程式人生 > >KMP演算法next陣列活用之前後綴問題

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;
    }
}

歡迎到微信裡去當吃瓜群眾