leetcode5 最長迴文子串(Manacher算法)
1.題目
給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲1000。
示例:
輸入: “babad”
輸出: “bab”
注意: “aba”也是一個有效答案。
2.manacher算法
奇迴文(如 aba)和偶迴文(如abba)歸一化處理
- 在字符串s的前端添加 $** 字符防止越界(代碼中有說明越界點),字符串s尾端已有 ‘\0’**
- 添加#字符於字符串s各字符之間
如abacddc
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
s[i] | a | b | a | c | d | d | c | \0 |
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s_new[i] | $ | # | a | # | b | # | a | # | c | # | d | # | d | # | c | # |
* 參數設定
id 爲當前最長迴文串的中心
mx 爲當前最長迴文串的右邊界
p[i] 爲以i爲中心的迴文串半徑
參考下圖:
關鍵點(動態規劃思想)
當 i 在當前最長迴文子串內時( mx>i ),以 i 爲中心的迴文子串長度:p[i] = max > i ? min(p[2*id - i], mx-i) : 1;
- 要麼等於其 關於id對稱點j爲中心的迴文子串長度(前提:以j爲中心的迴文子串包含在當前最長迴文子串內)
- 要麼以其爲中心的迴文子串右端 超出mx ( 此時p[i]設爲mx-i,且繼續尋找邊界 )
3.代碼
string longestPalindrome(string s) {
int max_str = 0; // 最長迴文子串的長度
int front_index; // 最長迴文子串的起始位
if(s.empty())
return 0;
// 初始化s
string new_s;
new_s.push_back('$');
new_s.push_back('#');
for(int i = 0; i < s.length(); i++)
{
new_s.push_back(s[i]);
new_s.push_back('#');
}
vector<int> p(new_s.length());
int id = 0;
int mx = 0;
for(int i = 1; i < new_s.length(); i++)
{
// p[i]爲當前i位置迴文子串的半徑,迴文子串長度爲p[i] - 1
// 加速方式(動態規劃):p[i] = max > i ? min(p[2*id - i], mx-i) : 1;
if(mx > i)
p[i] = min(p[2*id - i], mx-i);
else
p[i] = 1;
// 前後搜索,越界點
while(new_s[i + p[i]] == new_s[i - p[i]])
p[i]++;
if(p[i] - 1 > max_str){
front_index = (i - p[i] + 2)/2 - 1; // 一定是 #......# 的形式
max_str = p[i] - 1;
}
if(p[i] + i > mx){
mx = p[i] + i;
id = i;
}
}
return s.substr(front_index, max_str);
}