5. 最長迴文子串

關關的刷題日記發表於2018-04-03

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 長度最長為1000。

示例:

輸入: "babad"

輸出: "bab"

注意: "aba"也是有效答案

 

示例:

輸入: "cbbd"

輸出: "bb"

 

方法1: 用馬拉車演算法(字串動態規劃)來求最長迴文子串時間複雜度可以達到O(n).

可以參考這篇部落格:https://www.cnblogs.com/grandyang/p/4475985.html,寫的很好。

但是部落格裡面有個小失誤:這個id應該不是最大回文字串中心的位置,而是所有的迴文子串中,能延續到最右端的位置的那個迴文子串的中心點位置,mx是迴文串能延伸到的最右端的位置,這個應該沒錯,是id錯了,兩個沒對應上。我一開始按照id是最大回文字串中心的位置來寫了一段程式碼,也過了,後來發現根本不對,那樣的話時間複雜度就達不到O(n),因為比如說一個特別特別長的字串,一開始有一個最大回文子串,然後接下來的那些字串匹配的時候就都用不上前面的匹配結果,都需要匹配很多次,時間複雜度就達不到O(n)了。resCenter是最大回文子串的中心位置才對。

#include<iostream>
#include<string>
#include<vector>
#include <algorithm>
using namespace std;

string Manacher(string s)
{
	//預處理,加"#"
	string t = "$#";
	for (char x : s)
	{
		t += x;
		t += "#";
	}

	vector<int>p(t.size(), 0);
	int id = 0, mx = 0,i, resCenter=0, resLength=0;
	for (i = 1; i < t.size(); ++i)
	{
		p[i] = mx> i ? min(mx - i, p[2 * id - i]) : 1;
		while (t[i - p[i]] == t[i + p[i]])
			++p[i];
		if (mx < p[i] + i)
		{
			mx = p[i] + i;
			id = i;
		}
		if (p[i] > resLength)
		{
			resCenter = i;
			resLength = p[i];
		}
	}
	return s.substr((resCenter - resLength) / 2, resLength - 1);
}

int main()
{
	string s1 = "12212";
	cout << Manacher(s1) << endl;
	string s2 = "122122";
	cout << Manacher(s2) << endl;
	string s = "waabwswfd";
	cout << Manacher(s) << endl;
	return 0;
}

方法2:採用中心點擴散的方法,時間複雜度是O(n^2)。

class Solution {
public:
    string longestPalindrome(string s)
    {
        //將原始字串預處理變成奇數個
        string t;
        t += "$#";
        for (int x : s)
        {
            t += x;
            t += "#";
        }

        int resLen=0, resCen=0;
        for (int i = 1; i < t.size(); ++i)
        {
            int temp=0;
            while (t[i + temp] == t[i -temp]) ++temp;
            if (temp > resLen)
            {
                resLen=temp;
                resCen=i;
            }
        }
        return s.substr((resCen - resLen)/2, resLen - 1);
    }
};

 

相關文章