hihocoder:1032 : 最長迴文子串

一、問題描述

現給定一個已知的字符串str[],現在想要在O(n)的時間複雜度之內求出一個最長的迴文子字符串(正着和倒着順序讀一致)。

Manacher最早發現了可以用O(n)的時間複雜度來解決該問題,所以這種方法稱之爲Manacher算法。

二、符號說明

P[]存放的是迴文子串的半徑

三、Manacher算法主要思想

Manacher算法精髓就是對稱的思想,

假設i是我們將要計算迴文串半徑的字符,就是下一步我們要計算P[i]。
我們已知:
1,以id爲中心,P[id]爲半徑的範圍正好可以覆蓋i;  if (id+P[id]>i)
2,  以id爲對稱中心,i的對稱點是j,P[j]我們正好也知道。
可以得到:
P[i]>=min(P[id]-(id-j),  P[j]);
原因:如果j的半徑較小,那麼i的半徑必須等於P[j],(如果i的半徑比j大,又因爲i和j關於id對稱,兩者就矛盾了,所以i的半徑在這種情況下只能等於j的半徑);如下圖由對稱性1和2相等,2和3相等,3和4相等——》p[j]>p[j] 矛盾! 所以i的半徑必須等於P[j]!

如果j的半徑較大,那麼i的半徑只能等於P[id]-(id-j)(假設i的半徑大於P[id]-(id-j),由於對稱性,則j的半徑要大於P[j],這也於已知矛盾。)如下圖:如下圖由對稱性1和2相等,2和3相等,3和4相等——》p[id]>p[id] 矛盾! 所以i的半徑必須等於P[id]-(id-j)


    除此之外,就是P[id]爲半徑的範圍沒有覆蓋i;  
     這種情況就只能i以自己爲中心計算半徑了。


四  代碼:
和上面圖像有些不同,代碼裏的對稱中心是j,所以以j爲中心i的對稱點就是2 * j - i,
for (int i = 1; i < len; i++)
    {
        if (j+P[j]>i)  //這種情況,j才能作爲i的對稱中心來簡化計算,算法的精髓在P[i] >=min(P[2 * j - i],j+P[j]-i);
        {
            P[i] = min(P[2 * j - i],j+P[j]-i);
        }
        else        //這種情況,p[i]要重新計算,
        {
            P[i] = 1;
        }
        while (newstr[i + P[i]] == newstr[i - P[i]] && i + P[i] <= len)//以i爲對稱中心,看i兩邊的元素是否相等,更新p[i]
        {
            P[i]++;
        }
        if ((j + P[j]) < i + P[i])
            j = i;
        if (P[i]>maxlength)//maxlength用來統計最長的迴文串長度
            maxlength = P[i];
    }
    return;
} 









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