1. 程式人生 > >LeetCode5.最長迴文子串————Manacher演算法

LeetCode5.最長迴文子串————Manacher演算法

給定一個字串 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圈,直至最後一個字元】
用於計算字串中最大的迴文子串

新增虛位
計算迴文半徑陣列
可能性:

  1. i 在當前 R 外面 =>> 暴力直接擴 R 【暴力迴圈比較判斷,以 i 為中心進行迴文判斷】
  2. 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;//當前最右