1. 程式人生 > >【最長迴文子序列】hihocoder1032 C++

【最長迴文子序列】hihocoder1032 C++

問題描述

Time Limit:1000ms Case Time Limit:1000ms Memory Limit:256MB 小Hi和小Ho是一對好朋友,出生在資訊化社會的他們對程式設計產生了莫大的興趣,他們約定好互相幫助,在程式設計的學習道路上一同前進。 這一天,他們遇到了一連串的字串,於是小Hi就向小Ho提出了那個經典的問題:“小Ho,你能不能分別在這些字串中找到它們每一個的最長迴文子串呢?” 小Ho奇怪的問道:“什麼叫做最長迴文子串呢? 小Hi回答道:“一個字串中連續的一段就是這個字串的子串,而回文串指的是12421這種從前往後讀和從後往前讀一模一樣的字串,所以最長迴文子串的意思就是這個字串中最長的身為迴文串的子串啦~” 小Ho道:“原來如此!那麼我該怎麼得到這些字串呢?我又應該怎麼告訴你我所計算出的最長迴文子串呢? 小Hi笑著說道:“這個很容易啦,你只需要寫一個程式,先從標準輸入讀取一個整數N(N<=30),代表我給你的字串的個數,然後接下來的就是我要給你的那N個字串(字串長度<=10^6)啦。而你要告訴我你的答案的話,只要將你計算出的最長迴文子串的長度按照我給你的順序依次輸出到標準輸出就可以了!你看這就是一個例子。”

輸入輸出

Sample Input

3
abababa
aaaabaa
acacdas

Sample Output

7
5
3

程式碼

第一次做這個問題,用了簡單的暴力搜尋,以每個字串為中心左右擴充套件判斷是否相等,記錄下最大的迴文子串

#include <iostream>
#include <cstring>
using namespace std;
bool huiwen(string str,int len)
{
    bool flag = 1;
    for(int i = 0;i < len/2;i ++)
    {
        if(str[i] != str[len-i-1])
        {
            flag = 0;
            break;
        }
    }
    if(flag == 1) return true;
    else return false;
}
int main()
{
    int n;
    string str;
    cin >> n;
    for(int i = 0;i < n;i ++)
    {
        cin >> str;
        int len = str.length(),lens = len;
        while(lens > 1)
        {
            bool flag = 0;
            for(int j = 0;j < lens;j ++)
            {
                string s = str.substr(j,lens);
                if(huiwen(s,lens))
                {
                    cout<<lens<<endl;
                    flag = 1;
                    break;
                }
            }
            if(flag == 1) break;
            else lens--;
        }
    }
    return 0;
}

這樣做時間複雜度是O(n^2),肯定超時啦,題目中給出了提示,要利用之前搜尋過的回 文串資訊,來減少重複搜尋次數,於是去查了一波,動態規劃可以解決,但時間複雜度 為O(n^2),最優的是Manacher 演算法可以以O(n)的複雜度解決這個問題,這篇講的很詳細: 最長迴文子串—Manacher 演算法

#include <iostream>
#include <cstring>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
	string s;
	int n;
	cin >> n;
	for(int j = 0;j < n; j++)
	{
		cin >> s;
		int len = s.length();
		string str = "#" ;
		for(int i = 0;i < len;i ++)
		{
			str = str + s[i] + '#';
		}
		int len1 = str.length();
		int RL[len1];
		memset(RL,0,sizeof(RL));
		int MaxRight=0,pos = 0,MaxLen = 0;
		for(int i = 0;i < len1;i ++)
		{
			if(i < MaxRight)
				RL[i] = min(RL[2*pos - i], MaxRight - i);//i關於pos對稱位置的迴文半徑與i與MacRight之間的字元 
			else//若i大於MaxRight,則前面的迴文子串不包含i目前的迴文子串 
				RL[i] =  1;
			while((i - RL[i] >= 0)&&(i + RL[i] < len1) && (str[i - RL[i]] == str[i + RL[i]]))//判斷邊界和兩邊是否相等 
			{
				RL[i] ++;
			}
			if((RL[i] + i - 1) > MaxRight)//重置MaxRight和pos位置 
			{
				MaxRight = RL[i] + i - 1;
				pos = i;
			}
			MaxLen = max(MaxLen,RL[i]);
		}
		cout<<MaxLen - 1<<endl; //因為加了#所以要減一 
	}
	return 0;
}

然而再次遺憾超時!!想不出來優化了,求指點!