1. 程式人生 > >求最長迴文子串(多種解法)

求最長迴文子串(多種解法)

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

解析:

1.暴力解法,時間複雜度O(n^3),此種方法時間超出,未能AC。

string longestPalindrome(string s) {
	int i, j, len = s.length();
	int maxn=0,cnt = 0;
	string res="";
	for (i = 0; i<len; ++i){
		for (j = i; j<len; ++j){
			for (int k = 0; j - k >= 0 && i + k <= len&&i + k <= j - k; ++k){
				if (s[i + k] == s[j - k]){
					cnt++;
				}
				else{
					break;
				}
			}
			if (((j - i + 1) % 2==0 && cnt == (j - i + 1) / 2)||((j-i+1)%2==1&&(cnt==(j-i+1)/2+1))){
				if (j - i >= maxn){
					maxn = j - i;
					res = s.substr(i, j - i + 1);
				}
			}
			cnt = 0;
		}
	}
	return res;
}
2.動態規劃解法

假設dp[i][j]的值為true,表示字串s中下標從i到j的字元組成的子串是迴文串。那麼可以推出:

dp[i][j]=dp[i+1][j-1]&&s[i]==s[j]

這是一般的情況,由於需要依靠i+1,j-1,所以有可能i+1=j-1,i+1=(j-1)-1,因此需要求出基準情況才能套用以上公式。

a. i+1 = j-1 ,即迴文長度為1時,dp[i][i]=true;

b. i+1 = (j-1)-1,即迴文長度為2時,dp[i][i+1]=(s[i]==s[i+1])。

string longestPalindrome02(string s){
	int n = s.length();
	bool **dp = new bool*[n];
	for (int i = 0; i < n; ++i){
		dp[i] = new bool[n];
	}
	//基準情況
	int start = 0;
	int max = 1;
	for (int i = 0; i < n; ++i){
		dp[i][i] = true;
		if (i + 1 < n){
			if (s[i] == s[i + 1]){
				dp[i][i + 1] = true;
				start = i;
				max = 2;
			}
			else dp[i][i + 1] = false;
		}
	}
	//動態規劃求解,前面已經求解了len = 1 ,len = 2的情況了
	for (int len = 3; len <= n; ++len){
		for (int i = 0; i < n - len + 1; ++i){
			int j = i + len - 1;
			if (dp[i+1][j-1]&&s[i]==s[j]){
				dp[i][j] = true;
				int curLen = j - i + 1;
				if (curLen>max){
					start = i;
					max = curLen;
				}
			}
			else dp[i][j] = false;
		}
	}
	for (int i = 0; i < n; ++i){
		delete[] dp[i];
	delete[] dp;
	return s.substr(start,max);
	}
}
此種方法 記憶體超出,未能AC。


3.中心擴充套件法

因為迴文字串是以中心軸對稱的,所以如果我們從下標i出發,用2個指標向i的兩邊擴充套件判斷是否相等,那麼只需要對0到n-1的下標都做此操作,就可以求出最長的迴文子串。

但需要注意的是,迴文字串有奇偶對稱之分,即“abcba”和“abba”2種類型。

因此需要在程式碼中做出判斷。

設int Palindromic(string &s,int i,int j)是求下標i和j向兩邊擴充套件的迴文串的長度,那麼對0至n-1的下標,呼叫兩次此函式:

int lenOdd = Palindromic(str,i,i)和int lenEven = Palindromic(str,i,j),即可求得以i下標為奇迴文和偶迴文的子串長度。

接下來以lenOdd和lenEven中的最大值與當前最大值max比較即可。

這個方法有一個好處是時間複雜度為O(n^2),且不需要使用額外的空間。

class Solution {
public:
    string longestPalindrome(string s){
    	int n = s.length();
    	int start = 0;
    	int maxn = 1;
    	for (int i = 0; i < n; ++i){
    		int oddLen = 0, evenLen = 0, curLen;
    		oddLen = Palindromic(s, i, i);
    		if (i + 1 < n){
    			evenLen = Palindromic(s, i, i + 1);
    		}
    		curLen = oddLen > evenLen ? oddLen : evenLen;
    		if (curLen>maxn){
    			maxn = curLen;
    			if (maxn & 0x1){
    				start = i - maxn / 2;
    			}
    			else{
    				start = i - (maxn - 1) / 2;
    			}
    		}
    	}
	return s.substr(start, maxn);
    }
public:
    int Palindromic(string &str,int i,int j){
    	int n = str.length();
    	int curLen = 0;
    	while (i >= 0 && j < n&&str[i] == str[j]){
    		--i; ++j;
    	}
    	curLen = (j - 1) - (i + 1) + 1;
    	return curLen;
    }
};
46ms,AC

第四種解法:Manacher演算法的O(n)的演算法,下次更新