Manacher算法筆記 C++

Manacher算法簡介:

1.做用:Manacher算法又名馬拉車算法,用來求一個字符串中最長迴文子串的長度。ios

2.複雜度分析:時間複雜度爲O(n)。算法

算法核心思想:

1.僞代碼:假設str爲待判斷的字符串,len[ i ]數組存放以該 str[ i ] 字符爲中心的最長迴文子串的長度,mid爲當前最長迴文子串的中點,mx爲當前最長迴文子串的右邊界,那麼對當前位置 i 有以下僞代碼:(此時以知道前 i - 1個字符中最長迴文子串的長度以及以每一個字符爲中心的最長迴文串的長度)數組

  1. 若 i < mx,則 len[ i ] = min ( len[ 2*mid - i ] , mx - i )。
  2. 不然len[ i ] = 1。
  3. 對 i 位置上的字符向兩邊進行匹配,更新len[ i ]的值,更新結束後更新mid和mx的值。

2.算法思路:爲什麼能按照這樣步奏執行算法呢?spa

2.1 i < mx : code

首先,若是 i < mx,說明字符 str[ i ] 在以mid爲中心的迴文串中,那麼其與以 str[ j ]( i 關於 mid 的對稱位置)爲中心的最長迴文串有關。而以 str[ j ]字符爲中心的最長迴文串有三種可能:blog

  • 一種是該串(以j爲中心的最長迴文串)仍在以mid爲中心的最長迴文串中
  • 一種是超出
  • 最後一種是恰好相等

咱們能夠證實第一種與第二種狀況下,以 str[ i ] 爲中心的最長迴文串的長度爲len[ j ] 或 mx - i。[ 註釋1 ]而第三種狀況下,以str[  i ] 爲中心的迴文串長度卻可能大於len[ j ],故須要走僞代碼中的第3步來更新len[ i ] 。字符串

2.2 i >= mx :string

而若是i >= mx 狀況下,說明以 i 爲中心的最長迴文串沒法從以前獲得的len[ 1 ~ i -1]中得知,只能先令len[ i ] = 1,再分別向兩邊拓展,判斷迴文長度了,故走僞代碼中二、3步。io

註釋1:證實第1、第二中狀況下以str[ i ]爲中心的最長迴文串的長度爲len[ j ] 或 mx - i。模板

  • 若以str[ j ]爲中心的最長迴文串仍在以str[ mid ]爲中心的迴文串中,那麼因爲 i 與 j 關於mid對稱,以下圖,a != b,而d = a,c = b,故c != d,故len[ i ] = len[ j ]。

  • 若以str[ j ] 爲中心的最長迴文串超過了以str[ mid ]爲中心的最長迴文串,同理可證實以str[ i ] 爲中心的迴文串不可能與以str[ j] 爲中心的最長迴文串相等。

模板

//Manacher
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 1e5;
char str[MAXN];
char tmp[2*MAXN];
int len[2*MAXN];
int Manacher(char str[]){
	tmp[0] = '$';
	tmp[1] = '#';
	int str_len = strlen(str);
	for(int i = 1;i <= str_len;i++){
		tmp[2*i] = str[i-1];
		tmp[2*i+1] = '#';
	}
	tmp[2*str_len+2] = '\0';
	//cout << tmp << endl;
	int mx = 0;
	int maxlen = -1;
	int mid;
	for(int i = 1; tmp[i]; i++){
		if(i < mx) len[i] = min(len[2*mid-i],mx-i);
		else len[i] = 1;
		while(tmp[i-len[i]] == tmp[i+len[i]]) len[i]++;
		if(len[i]+i > mx){
			mx = len[i]+i;
			mid = i;
		}
		maxlen = max(maxlen,len[i]-1);
	}
	return maxlen;
}
int main(){
	scanf("%s",str);
	cout << Manacher(str);
	return 0;
}
相關文章
相關標籤/搜索