(算法)最长回文子串

题目:

求一个字符串的最长回文子串

思路:

1、暴力枚举

最容易想到的就是暴力破解,列举每一个子串,然后根据回文的定义判断是不是回文,找到最长的那个。

求每一个子串的时间复杂度为O(N^2),判断子串是不是回文的时间复杂度为O(N),所以时间复杂度为O(N^3)。

2、动态规划

回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。

这样需要额外的空间是O(N^2),时间复杂度也是O(N^2)。

状态转移方程:

当str[i]=str[j] dp[i][j]=dp[i+1][j-1] 

当str[i]!=str[j] dp[i][j]=0

初始状态:

dp[i][i]=1

dp[i][i+1]=1 if str[i]=str[i+1]

3、中心扩展

中心扩展就是把给定的字符串的每一个字符当做中心,向两边扩展,这样来找最长的子回文串。时间复杂度为O(N^2)。

但是要考虑两种情况:

如aba,这样长度为奇数。

如abba,这样长度为偶数。

4、Manacher法

待续

代码:

#include<iostream>
using namespace std;

// brute force
string findLongestPalindrome_1(string &str){
	int length=str.size();
	int maxLength=0;
	int start;

	for(int i=0;i<length;i++){
		for(int j=i+1;j<length;j++){
			int left,right;
			for(left=i,right=j;left<right;left++,right--){
				if(str[left]!=str[right])
					break;
			}
			if(left>=right && (j-i)>maxLength){
				maxLength=j-i+1;
				start=i;
			}
		}
	}

	if(maxLength>0)
		return str.substr(start,maxLength);
	return NULL;
}


// dynamic programming
string findLongestPalindrome_2(string &str){
	const int length=str.size();
	int maxLength=1;
	int start;

	bool dp[length][length];

	for(int i=0;i<length;i++)
		for(int j=0;j<length;j++)
			dp[i][j]=false;

	for(int i=0;i<length;i++){
		dp[i][i]=true;
		if(i<length-1 && str[i]==str[i+1]){
			dp[i][i+1]=true;
			start=i;
			maxLength=2;
		}
	}

	for(int len=3;len<=length;len++){
		for(int i=0;i<=length-len;i++){
			int j=i+len-1;
			if(dp[i+1][j-1] && str[i]==str[j]){
				dp[i][j]=true;
				start=i;
				maxLength=len;
			}
		}
	}

	if(maxLength>=2)
		return str.substr(start,maxLength);
	return NULL;
}

// pivot expand
string findLongestPalindrome_3(string &str){
	const int length=str.size();
	int maxLength=1;
	int start;

	for(int i=0;i<length;i++){
		int left=i-1;
		int right=i+1;
		while(left>=0 && right<=length-1 && str[left]==str[right]){
			if(right-left+1>maxLength){
				start=left;
				maxLength=right-left+1;
			}
			left--;
			right++;
		}
	}

	for(int i=0;i<length;i++){
		int left=i;
		int right=i+1;
		while(left>=0 && right<=length-1 && str[left]==str[right]){
			if(right-left+1>maxLength){
				start=left;
				maxLength=right-left+1;
			}
			left--;
			right++;
		}
	}

	if(maxLength>0)
		return str.substr(start,maxLength);
	return NULL;
}


int main(){
	string str="ababcddcbbd";
	cout<<findLongestPalindrome_1(str)<<endl;
	cout<<findLongestPalindrome_2(str)<<endl;
	cout<<findLongestPalindrome_3(str)<<endl;
	return 0;
}

  

 

posted @ 2015-08-20 21:45  AndyJee  阅读(849)  评论(0编辑  收藏  举报