1. 程式人生 > >leetcode 214 Shortest Palindrome kmp演算法 字首字尾字串匹配

leetcode 214 Shortest Palindrome kmp演算法 字首字尾字串匹配

0 leetcode 214. Shortest Palindrome  本題的描述是一個串前方加上一些字串,使其成為一個迴文串。

形式類似於(新增部分)(迴文部分)(其餘部分),所以我們的目標就是將其迴文部分求出來,或者把他的長度求出來。

如果用暴力解法,那麼問題就變成O(N*N)的複雜度,我們希望優雅地解決,所以我們用到kmp演算法求nxt陣列。

kmp演算法是求字串匹配的演算法,下面記錄個人學習筆記。

 

1 串的匹配問題:用串p去匹配串s,意為比較串s中是否存在串p;普通的方法時間複雜度為o(n*m),因為每次都需要重新對串p進行比較;kmp演算法的作用就是用一個數組記錄模式串p的資訊,用於加快上述匹配任務,同時也有一些變形。

2 next陣列:上面說到用一個數組來記錄模式串p的資訊,這個陣列就是next陣列,它記錄了當前位置上,字首子串與字尾子串相等的最大的長度。那麼在求出next陣列之後,模式串在移動的時候,就不用在一個個地從頭開始移動了,而可以一次移動最大字首長度的距離。

3 next陣列的求法,這裡用一張圖來表示

在我們從1開始求nxt陣列的時候,一直求到nxt[j],此時我們需要利用到nxt[j-1]的資訊,令k = nxt[j-1],k的意思為:在模式串p[0,j-1](下標從0到下標j-2,共j-1個字元),字首字尾數目相同的字串的最大長度為k,如圖中的兩段陰影部分是相等的。那麼此時我們比較字首串的下一個字元p[k],與字尾串的下一個字元p[j-1]是否相同。如果兩者相同,那麼nxt[j] = nxt[j-1] + 1,相當於延長一個字首串長度。如果兩者不同,那麼我們要重新找字首樹和字尾樹相同的長度。(兩者相同的正確性證明:因為在nxt為j-1時性質成立,而且在nxt為j時,已經進行了自增,所以nxt一定為最大的字首串和字尾串的長度)

下面來解釋,如果字首串的下一個字元p[k],與字尾串的下一個字元p[j-1]不同時,如何處理。第一點,我們需要找的是字首串,與字尾串的最大長度,且字尾串的最後一個字元是p[j-1],所以我們每次找的時候,都是從p[k]附近找一個位置,然後和p[j-1]進行比較。第二點,字首串此時為p[0,k],但是我們沒有達到讓他增長,所以字首串必須進行縮短,所以從p[k]附近找縮小為從p[k]向前找。下面我們再用一張圖來表示

剛才我們說到,nxt[j-1]為k時,兩個陰影部分的字串是相等的,那麼我們同樣可以再nex[k]處得到這個結論:前面兩個深色陰影區域的字串是相等的,且長度都是nxt[k];並且由於對稱性,後面兩個深色陰影也是相等的。然後我們退一步看,如何儘可能地找到字首串和字尾串最長的的值呢?結論:這個串就是深色的第一個串+1.證明:因為我們有了結論--淺色串後面的一個字元不相同,所以我們把字首串給截短了,截短的最長的長度就是深色串(這個性質是nxt陣列維護的)。所以我們可以從深色串開始著手求下一個最長的字首陣列與字尾陣列相同的串。4 好的,到目前為止,我們對nxt的陣列分析結束,程式碼的話文末會提供實現。

4 好的,我們現在回到問題,怎樣求(新增部分)(迴文部分)(其餘部分)中迴文部分的長度呢,我們可以把問題變種,為求最長字首字尾匹配問題,所以要對字串做出一些變換。首先將字串翻轉,然後變為一個新字串,rev = reverse(s), l = s + “#” + rev

所以 l = (迴文部分)(其餘部分)#(其餘部分)(迴文部分),因為迴文串的對稱性,我們再對字串I求nxt陣列即可,但是注意nxt陣列的下標為記錄當前字元的之前的字元的最大長度,所以如果要直接利用kmp演算法的nxt陣列的話,還需要將字串l再延長一個長度,然後把nxt[l.size()-1]輸出為迴文串長度即可。

5 求nxt陣列的程式碼

vector<int> getnext(string p)//the next
{
    int n = p.size();
    vector<int> next(n, 0);
    next[0] = -1;
    for (int j = 1; j < n; ++j)
    {
        int k = next[j - 1];
        while (k != -1 && p[k] != p[j - 1])
            k = next[k];
        next[j] = k + 1;
    }
    return next;
}

6 referenct 

https://blog.csdn.net/v_july_v/article/details/7041827