字串演算法

zyzzzzlh發表於2024-03-31

Manacher-------快速查詢回文串

這個演算法其實是基於暴力查詢回文串的最佳化。

	while(i-k>=0&&i+k<n&&s[i-k]==s[i+k]){
            k++;
        }

這就是暴力查詢以s[i]為中心點的奇數長的迴文串,偶數也一樣就是改一下下角標就可以。

這個演算法的最佳化其實就是以s[i]為中點的迴文串,左右兩邊會有相同的迴文串特點,也就是d1[i-k]=d1[i+k],但是要注意一個情況,i-k的迴文串長度可能會超出當前這個i的迴文串,那左邊滿足的右邊就不一定滿足。

k=min(d1[l+r-i],r-i+1);
這句就是在規避這一情況。

一旦當前位置已經跑出上一個迴文串的範圍就只能用暴力跑新的迴文串,沒有可以繼承的和它對稱的左半部分的迴文串中心了。

for(int i=0,l=0,r=-1;i<n;i++){//跑的是奇數長度的迴文串
        int k;
        if(i>r){
            k=1;//上次的迴文串已經結束了,只能暴力跑
        }
        else{
            k=min(d1[l+r-i],r-i+1);//有可能左邊那個點的迴文串長度超出上次的迴文串的邊界
        }
        while(i-k>=0&&i+k<n&&s[i-k]==s[i+k]){
            k++;
        }
        //k--;
        d1[i]=k--;

        if(i+k>r){//更新迴文串範圍
            l=i-k;
            r=i+k;
        }
    }
for(int i=0,l=0,r=-1;i<n;i++){//偶數長度的迴文串
        int k;
        if(i>r){
            k=0;
        }
        else{
            k=min(d2[l+r-i+1],r-i+1);
        }
        while(i-k-1>=0&&i+k<n&&s[i-k-1]==s[i+k]){
            k++;
        }
        //k--;
        d2[i]=k--;

        if(i+k>r){
            l=i-k-1;
            r=i+k;
        }
    }

偶數和奇數的差別就是邊界的判斷,偶數相當於就是把後面那個字元當做字串中心。

相關文章