LeetCode5.最長迴文子串————Manacher演算法
阿新 • • 發佈:2019-02-02
給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。
示例 1:
輸入: “babad”
輸出: “bab”
注意: "aba"也是一個有效答案。示例 2:
輸入: “cbbd”
輸出: “bb”
方法一: 動態規劃,O(n^2)
i 為做指標,j 為右指標。
dp[ i ][ j ]指:從i到j位置組成的字串是否迴文,迴文則1,否則0。
若str[ i ] = str[ j ],則dp[ i ][ j ]是否迴文取決於dp[ i + 1][ j - 1]是否迴文。
若str[ i ] != str[ j ],則dp[ i ][ j ]肯定不迴文。
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class Solution {
public:
//O(n^2)動態規劃
string longestPalindrome(string s) {
int i, j;
vector<vector<bool>> dp(s.size(), vector<bool>(s.size(), false));//儲存i到j子串是否迴文
int maxI = 0, maxJ = 0;//儲存最大回文子串的兩端位置i與j
int maxNums = 1;//儲存最大回文子串的字元數
for (j = 0; j < s.size(); ++j)
{
dp[j][j] = true;
for (i = j - 1; i >= 0; --i)
{
if (s[i] == s[j])//如果兩端字元相等
{
if (j - i == 1 || dp[i + 1][j - 1] != false)//如果兩端字元相鄰 - 或者 - 兩端字元內部的兩端仍是相等字元
{
dp[i][ j] = true;//從i到j位置的字串迴文
if (maxNums < j - i + 1)//獲取最大回文子串
{
maxNums = j - i + 1;
maxI = i;
maxJ = j;
}
}
else
dp[i][j] = false;
}//如果兩端字元不相等
else
dp[i][j] = false;//從i到j位置的字串不迴文
}
}
return s.substr(maxI, maxJ - maxI + 1);
}
};
方法二: Manacher演算法,O(n)
馬拉車演算法:【O(N),不斷擴大R圈,直至最後一個字元】
用於計算字串中最大的迴文子串
新增虛位
計算迴文半徑陣列
可能性:
- i 在當前 R 外面 =>> 暴力直接擴 R 【暴力迴圈比較判斷,以 i 為中心進行迴文判斷】
- i 在當前 R 內(i’ 為 i 圍繞當前中心 C 作的 [左邊] 對稱點)
- (1)i’ 位置的迴文半徑圈沒有超過當前 R 圈=>> i 位置的迴文半徑等於 i’ 的迴文半徑 【O(1)】
- (2)i’ 位置的迴文半徑圈超過了當前 R 圈 =>> i 位置的迴文半徑等於 i 位置到當前 R 位置 【O(1)】
- (3)i’ 位置的迴文半徑圈正好位於當前R圈 =>> i 位置到 R 位圈位置不用檢測,以後需要進行比較檢測,擴大當前最長迴文半徑 R,修改當前最長迴文中心 C 【暴力迴圈比較判斷,以i為中心進行迴文判斷】
//馬拉車演算法
string longestPalindrome(string s) {
//結果變數
int resultCenter = 0;//結果的迴文中心位置
int resultMaxRadius = 0;//結果的最大回文半徑值
//新增虛位‘#’
string sInput(1, '#');
for (int i = 0; i < s.size(); ++i)
{
sInput += s[i];
sInput.append("#");
}
vector<int> radiusStr(sInput.size(), 0);//迴文半徑陣列 【int radiusStr[sInput.size()] = { 0 };不出錯】
int rightCenter = -1;//當前最右