首頁>技術>

在中心擴充套件法中我們考慮了奇數和偶數兩種情況,而馬拉車演算法對它進行統一的思想是:在原字串的字元之間和首尾都插入一個字母

char* Init_manacher(char* s){    char* s_new = (char*)malloc(sizeof(char)*(2 * strlen(s) + 1));    int i = 0, j = 1;    s_new[0] = '#';    for (; i < strlen(s); i++, j++)    {        s_new[j++] = s[i];        s_new[j] = '#';    }    s_new[j] = '\0';    return s_new;}

s_new的長度變為了奇數,不管原來的字串是否奇數,這樣就可以統一處理奇數偶數長度了。

演算法的關鍵是:定義並計算陣列P[i],(P[i]表示以字元s_new[i]為中心的最長迴文子串的最右端字元到s_new[i]的距離,俗稱迴文半徑),算出P[i]的每一個值,求出最大的迴文半徑,就得出最長迴文子串。

所以問題就轉化為求陣列P[i]

馬拉車演算法

圖中,

id :為當前已經計算過的字串中,觸及右邊最遠的子串的中心點

mx :觸及右邊最遠子串所觸及的最遠的點

j是i的對稱點,根據對稱性可以得出,i + j = 2 * id,從而得出:

i的對稱點j用i表示的話就是: j = 2 * id - i (重點理解)

 p[i] = (p[2 * id - i]) < (mx - i) ? (p[2 * id - i]) : (mx - i);

那麼上面這句程式碼可以理解為:我要計算的p[i]可以用已經計算過的p[j](也就是p[2 * id - i]))計算;至於兩個值誰小等於誰的問題,接下來再討論。

 if (i < mx) {       p[i] = (p[2 * id - i]) < (mx - i) ? (p[2 * id - i]) : (mx - i);  } else {       p[i] = 1;  }

從上圖我們可以看出,條件i < mx,說明要求的迴文半徑p[i]可以使用對稱性求,得出的是p[j]和mx - i的最小值(此處下邊詳細解釋)。當i >= mx時,不能再使用對稱性求出,也就是說上一個迴文子串結束了,我們需要從1開始再計算一個新的迴文子串,如果它大於上一個迴文子串的長度,則就是答案。

詳細解釋:取p[j]和mx - i的最小值

一種如綠線的示意,以p[i]為迴文半徑的迴文子串的半徑小於mx - i,也就是說這個迴文子串沒超過mx,這種情況迴文半徑的取值就是p[j];

一種如黃線所示,以p[i]為迴文半徑的迴文子串的半徑大於mx - i,也就是說這個迴文子串超過了mx,所以它的迴文半徑最短也是mx-i,還可能大於它。但是我們不管它,只計算沒超過mx的部分。

所以這兩種情況綜合之後,就是取p[j]和mx - i的最小值

重新開始一個新的子串:

while (s_new[i - p[i]] == s_new[i + p[i]] && i + p[i] < len && i - p[i] > -1) {            p[i]++;        }

重新選取mx和id:

if (mx < i + p[i])        {            id = i;            mx = i + p[i];        }

如果有子串比之前的串更長則更新:

if (max_len < p[i]) {       max_len = p[i];       c = i;   }

完整程式碼:

10
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 做React開發,用函式元件還是類元件?