最長回文子串—動態規划和Manacher算法(0(n)時間復雜度


動態規划:
dp[i][j] = 1  i==j
dp[i][j] = dp[i+1][j-1] + 2   str[i] == str[j]
dp[i][j] = max(dp[i+1][j], dp[i][j-1])  str[i] != str[j],不相等,等於前面的的最大值
   由於計算第i個位置,需要第i+1 個位置,因此倒着計算


Manacher 

http://blog.csdn.net/avenger_tao/article/details/51056159



#include <iostream>
#include <string>
#include <vector>
using namespace std;
/**
* Manacher O(n)
* @param string str
*/
int manacher(string &str) {
int length = str.size() * 2 + 1;
string cur_str(length, '#');
// 字符串中間 插入 特殊字符
for (int i = 0; i < length; ++i) {
cur_str[i] = (i % 2 == 1 ? str[(i+1)/2 - 1] : '#');
}
cout << cur_str << endl;
vector<int> RL(length, 0); // 每一個位置的回文串 長度 (不包含特殊字符)
int maxLength= 0; // 最大長度
int pos = 0; // 當前最大字串對稱位置
int maxRight = 0; // 當前最大字串所能到達的最右邊
for (int i = 0; i < length; ++i) {
if (i >= maxRight) {
RL[i] = 1; // 超出最右位置,與之前的對稱串沒有關系
} else {
// 當前位置 在最大回文串里面(maxRight 左邊)
int j = 2 * pos - i; // i 關於pos對稱的j (j 以及求過)
RL[i] = min(RL[j], maxRight - i);
/* 因為 maxRight - i 的最大值是 maxRight - pos
* RL[j] 的 maxRight 如果超過pos,則肯定取 maxGight-i
*/
}
while (i - RL[i] >= 0 && i + RL[i] < length && cur_str[i-RL[i]] == cur_str[i+RL[i]]) {
RL[i]++;
}
// 對稱位置i + 回文串長度 (回文串長度 在cur_str里面是對稱半徑長度)
if (RL[i] - 1 + i > maxRight) {
maxRight = RL[i] + i - 1;
pos = i;
}
maxLength = max(maxLength, RL[i]);
}
return maxLength - 1;
}
/**
* 動態規划, O(n^2)
*/
int dpAlgorithm(string &str) {
int length = str.size();
vector<vector<int> > dp(length, vector<int>(length, 0));
for (int i = length - 1; i >= 0; i--) {
dp[i][i] = 1;
for (int j = i + 1; j < length; ++j) {
if (str[i] == str[j]) {
dp[i][j] = dp[i+1][j-1] + 2;
} else {
dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
}
}
}// end for
return dp[0][length-1];
}
int main()
{
string str;
while (cin >> str) {
cout << dpAlgorithm(str) << endl;
cout << manacher(str) << endl;
}
return 0;
}



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com