タイトル
文字列が与えられ、S、最長の回文構造部分文字列を見つけるのを。あなたは、最大長さと仮定してよいのは、 1000です
:例1
の入力:「babad」
出力:「BAB」
注:「ABAも有効な回答である。」
例2:
入力:「cbbd」
出力:「BB」
考え
アイデア1:動的計画
ステップ1:最適解の方程式を描きます
\(DP [I] [jを ] \) サブストリングを表し\(S [I、\ cdots 、J] \) パリンドロームは、サブストリングかどうかを
ステップ2:最適解の再帰的定義の値
(1)初期化:
- DP [i]は[I] = TRUE、I = [0、1、...、N-1]。
- DP [i]は[I-1]真= I = [1,2、...、N-1]
- 残りは偽であります
(2)状態遷移表
- DP [I] [J] =(S [I] == S [J] && DP [I + 1] [J-1])
図1に示した状態遷移表を更新します。
ステップ3:計算最適解
状態遷移テーブル、および漸化式演算DP [I] [J]。
アイデア2:センターの拡張方法
文字の中央には、回文の長さを計算しました。パリンドロームストリングは、両方の場合で、偶数、奇数に分割されています
- 奇数:現在の決意を中心にキャラクターを移動します
さえ:中央審査員として現在トラバーサル文字とその隣接する文字
3考える:Manacherアルゴリズムを
また、馬車車アルゴリズムとして知られている、我々はパリンドローム問題を解決することができる最長の文字列の部分文字列の時間複雑性O(n)の場合です。
図1に示すように、(サブストリングの長さが奇数パリンドロームであるように)長さが奇数と一緒に考慮パリンドローム配列の部分長の偶数になるように、仮想列#(#は実際に増加していない)を増加させるManacherアルゴリズム。行うには:頭、尾、隣接する文字列仮想上昇#記号の間。プロパティ(1)レン配列
コンピューティング(2)レンアレイ
アイデア4:文字列のスライス(パイソン)
パリンドロームは、スライスの文字列を使用しているかどうかを検出します。
ヒント
ダイナミックプログラミング
C ++
- アイデア1
class Solution {
public:
string longestPalindrome(string s) {
int nLength = s.size();
if(nLength<1)
return s;
vector<vector<bool> > dp(nLength, vector<bool>(nLength, 0)); //dp[i][j]表示子串s[i,...,j]是否是一个回文子串
int strBegin = 0; //回文子串的开始
int strEnd = 0; //回文子串的结尾
//初始化
for(int i = 1;i < nLength; i++){
dp[i][i] = true;
dp[i][i-1] = true; //这个是针对子串长度为2,"bb"、"aa"的情况
}
dp[0][0] = true;
//动态规划
for(int i = 2;i <= nLength; i++){ //回文长度
for(int j = 0; j <= nLength - i ; j++){ //回文子串起始
if(s[j] == s[i+j - 1] && dp[j+1][i+j-2]){
dp[j][j+i-1] = true;
if(strEnd - strBegin + 1 < i){
strBegin = j;
strEnd = i + j -1;
}
}
}
}
return s.substr(strBegin,strEnd-strBegin+1);
}
};
- アイデア2
class Solution {
public:
string longestPalindrome(string s) {
int nLength = s.size();
if(nLength == 1)
return s;
int strBegin = 0;
int maxLength = 0;
for(int i = 1;i < nLength; i++){
//如果回文子串是奇数,以i为中心搜索
int left = i - 1;
int right = i + 1;
while(left >=0 && right < nLength && s[left] == s[right] )
{
left --;
right ++;
}
if(right - left - 1 > maxLength){ //right -1 - (left + 1) + 1
maxLength = right - left - 1;
strBegin = left + 1;
}
//如果回文子串是偶数,
left = i - 1;
right = i;
while(left >=0 && right < nLength && s[left] == s[right]){
left --;
right ++;
}
if(right - left - 1 > maxLength){
maxLength = right - left - 1;
strBegin = left + 1;
}
}
return s.substr(strBegin,maxLength);
}
};
- 3つのアイデア
class Solution {
public:
string longestPalindrome(string s) {
if(s.size() <= 1)
return s;
string dummy = init(s);
int nLength = dummy.size();
int maxLen = 0;
int mx = 0;
int id = 0;
vector<int> len(nLength, 0);
for(int i =1;i< nLength - 1; i++){
if(i < mx)
len[i] = min(len[2*id -1], mx - i);
else
len[i] = 1;
if(s[i - len[i]] == s[i + len[i]])
len[i] ++;
if(mx < i + len[i]){
id = i;
mx = i + len[i];
}
}
int index = 0;
for(int i = 1; i < nLength-1; i++){
if(len[i] > maxLen){
maxLen = len[i];
index = i;
}
}
return s.substr((index - maxLen)/2, maxLen-1);
}
//初始化
string init(const string& s){
string result = "$#";
int nLength = s.size();
for(int i=0;i < nLength; i++){
result.push_back(s[i]);
result.push_back('#');
}
return result;
}
};
パイソン
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
# 如果s为空
if len(s) == 1:
return s
result = ""
for i in range(len(s)):
j = i + 1
while j < len(s) and len(result) <= len(s[i:]):
if s[i:j] == s[i:j][::-1] and len(s[i:j]) > len(result):
result = s[i:j]
j += 1
return result