如何證明Manacher演算法的時間複雜度是O(n)?
就是求最長迴文子串的那個演算法
謝邀:
我希望:題主事先已經知道了Manacher這個演算法,以及該演算法的細節,以及能看得懂這個鏈接裡面的介紹hdu3068之manacher演算法+詳解,如果不能做到以上幾點,那麼我沒什麼好講的。然後我結合鏈接裡面的內容講一下時間複雜度。

如果我們能證明maxlen或i+k的每增加1隻需要有限個單位的時間,而當maxlen增加到2n+1時這個演算法也就結束了,或者當i+k=2N+1時這個演算法也就結束了。

現在
我們現在證明maxlen或i+k的每增加1隻需要有限個單位的時間如下圖
第一種.單位時間,讓i+k向右移動一下,(那個橙色不可能超過黑色線右端,一旦超過,黑色線就得重畫,而橙色線本身可以到達黑色線右端,所以直接就是結果,也就是即使寫了while也必定會在第一次循環)



- 核心代碼
void manacher(char* s)
{
int c = 0, r = 0;
p[0] = 0;
for( int i = 1; s[i]!=" " ; ++i ) {
if( r &> i ) p[i] = min( p[ 2 * c - i ], r - i );
else p[i] = 0;
while( s[i + 1 + p[i]] == s[i - 1 - p[i]] ) p[i]++;
if( i + p[i] &> r ) {
r = i + p[i];
c = i;
}
}
}
- 演算法複雜度
從代碼可以看出。
manacher演算法只需要線性掃描一遍預處理後的字元串。對
1. 在的情況下,p的值可以在
時間內確定
- 只需要弄清楚兩點
- while()循環本身的時間複雜度在沒有前提條件的情況下確實是
- 但是這裡的
(也就是上面答案中的
),是不斷往後走而不可能往前退的,它自身的值的變化是遞增的。那麼你可以明白,要進入while循環,
的值必然是比
大的,也就是說整個程序結束為止,while循環執行的操作數為
次(線性次),而字元串中的每個字元,最多能被訪問到2次。時間複雜度必然為
兩個指針必然有一個至少挪動一位,而且消耗時間和位移動成正比,而且不會向左移。
剛想了想,整理了下思路,不知道對不對。
比較次數的多少是和 (迴文最右邊位置)有關的,也就是說複雜度是和
從
位置移動到
的位置次數是線性相關的,
從
移動到
位置最多為
次,因此演算法的時間複雜度是
。
--------------------------------------------------------------------------------------------------------------------------
下面嘗試下證明。
設比較第 個字元時比較次數為
,此時
的位置記為
(上一次比較後
的位置)。比較完成後
的位置記為
。
總比較次數
所以Manacher演算法的複雜度是嚴格 的。
for(int i = 1; i &< n - 1; i++)
{
j = 2*id - i;
if(maxLen &> i)
p[i] = std::min(maxLen - i + 1, p[j]);
else
p[i] = 1;
while (i-p[i] &>=0 i + p[i] &< n mStr[i + p[i]] == mStr[i - p[i]])
p[i]++;
//計算id及maxLen
if (i + p[i] &> maxLen)
{
maxLen = i + p[i] - 1;
id = i;
}
}
@白榮東 我想,樓主想問的是為什麼下面這個循環的時間複雜度與n無關。
如果按照直覺,這個循環可能與n有關。while (i-p[i] &>=0 i + p[i] &< n mStr[i + p[i]] == mStr[i - p[i]])
p[i]++;
推薦閱讀:
※如何看待用中國大陸地區境內的搜索引擎搜索主席樹得到的結果文不對題?
※有哪些演算法是中國人自己創造的?
※有哪些有趣的樹結構的表示方法?
※背包問題是否本質上都是DP?
※用Python刷面試演算法題(如leetcode)是怎樣的體驗?
