Longest Palindromic Substring 最长回文子串

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

示例 1:

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

示例 2:

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

思路:首先给出动态规划解法的时间复杂度O(n^2),需要维护一个二维数组dp[i][j],其中dp[i][j]表示从字符串的s[i]到s[j](包含s[j])是回文序列,dp[i][j]是回文序列,则dp[i][j]赋值为true,我们只需要返回i和j间隔最大的子字符串即可。

这里先给出递归公式:

dp[i, j] = true                                        if i == j

         = s[i] == s[j]                              if j = i + 1

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

解释:如果i==j,即中只有一个字符的情况,s[i]当然等于自身,所以赋值为true。如果j=i+1(这里为什么相邻的要单独讨论,因为相邻的没法找到他的子集的情况,及s[i+1]到s[j-1]这种情况,比较特殊,所以单独考虑),如果相等就把dp[i][j]赋值为true。最后一种情况,如果i和j相差3个及以上,就判断他的子集dp[i+1][j-1](想等于向内收缩)以及自身是否相等,如果相等,就把dp[i][j]赋值为true,以下为一个图例说明情况。


由于我们判断的是序列[i,j]是否是回文序列,所以对于左下角部分不用讨论(红色圆圈所示),对二维数组的遍历我们采用红色线所示的路径进行,而不是传统的如下遍历方式:

for(int i=0;i<n;i++){
   for(int j=0;j<n;j++){
       //blabla
   }
}

因为如下图所示,我们在递归条件式中可以看到,当前状态更新需要用到dp[i+1][j-1]的值,从图像上来看就是需要左下角状态的信息(如图所示,绿色更新需要需要橘黄色的状态作为前提(假设不考虑j-i>2的情况,这里只是示例)),所以我们需要由底向上,由左向右的更新方式。


参考代码:

    string longestPalindrome(string s) {
	string res;
	bool **dp = new bool *[s.size()];
	for (int i = 0; i < s.size(); i++) {
		dp[i] = new bool[s.size()]{false};
	}
	int n = s.size();
	for (int i = n - 1; i >= 0; i--) {
		for (int j = i; j < n; j++) {
			dp[i][j] = s[i] == s[j] && ((j - i) < 3 || dp[i + 1][j - 1]);
			if (dp[i][j] && (res.size() == 0 || (j - i + 1) > res.size())) {
				res = s.substr(i,j-i+1);
			}
		}
	}
	for (int i = 0; i < s.size(); i++) {
		delete[] dp[i];
	}
	delete[] dp;
	return res;        
    }







猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/80732431