Leetcode:最长回文子串

题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
测试案例

输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

输入: "cbbd"
输出: "bb"

解法

首先是最容易想到的复杂度最高的朴素遍历解法:

class Solution {
public:
string longestPalindrome(string s) {
	if (s.empty()) return "";
	if (s.size() == 1) return s;
	int start=0,maxLength = 1;
	for (int i = 0; i < s.size(); ++i)
	{
		for (int j = i + 1; j < s.size(); ++j)
		{
			int fFirst = i, fLast = j;
			for (; fFirst < fLast; fFirst++, fLast--)
			{
				if (s[fFirst] != s[fLast])
					break;
			}
			
			if (fFirst >= fLast && j - i + 1 > maxLength)
			{
				maxLength = j - i + 1;
				start = i;
			}
		}
	}
	return s.substr(start, maxLength);
}
};

然后在介绍一种动态规划的方法:
\(dp[i,j]= \begin{cases} dp[i+1,j-1]& \text{s[i]=s[j]}\\ 0& \text{s[i]!=s[j]} \end{cases}\)
上面的状态转移方程表示,当s[i]=s[j]时,如果s[i+1...j-1]是回文串,则s[i...j]也是回文串;如果s[i+1...j-1]不是回文串,则s[i...j]不是回文串。

string longestPalindrome(string s) {
	if (s.empty()) return "";
	if (s.size() == 1) return s;
	int len = s.size(),start=0,maxLength=1;
	vector<vector<int>> dp(len, vector<int>(len));

	//首先判断相邻2个字符
	for (int i = 0; i < len; ++i)
	{
		dp[i][i] = 1;
		if (i < len - 1)
		{
			if (s[i] == s[i + 1])
			{
				dp[i][i + 1] = 1;
				start = i;
				maxLength = 2;
			}
		}
	}

	//再从字符串长度为3开始判断
	for (int l = 3; l <=len; ++l)
	{
		for (int i = 0; i+l-1 < len ; ++i)
		{
			int j = l+ i - 1;
			if (s[i] == s[j] && dp[i + 1][j - 1] == 1)
			{
				dp[i][j] = 1;
				start = i;
				maxLength = l;
			}
		}
	}
	return s.substr(start, maxLength);
}

我们可以这样想,一个字符的话是回文字串,直接返回u;如果是两个相同的字符的话,那么字符串最长回文字符串的长度为2;之后利用动态规划的思想,如果一个新的字符串(原字符串的子串)的首尾字符相同,同时除了首尾的字符串刚好是上一个动态规划的结果,那么就可以将这个字符串作为下一次判断的依据,如果下一次不是则就保存结果。代码中dp[i+1][j+1]就是上一次的字符串判断结果。

然后贴一下大神的Manacher解法

posted @ 2018-09-07 00:23  MrYun  阅读(87)  评论(0编辑  收藏  举报