【LeetCode】5.最长回文子串

版权声明:非商业性使用,禁止演绎,转载请保留原文链接及作者 https://blog.csdn.net/qq_39478237/article/details/89457230

题目描述

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

示例 1:

输入: "babad"
输出: "bab"

注意: “aba” 也是一个有效答案。
示例 2:

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

思路一

常见错误

有些人会忍不住提出一个快速的解决方案,不幸的是,这个解决方案有缺陷(但是可以很容易地纠正):

反转S,使之变成S′。找到S 和S′   之间最长的公共子串,这也必然是最长的回文子串。

这似乎是可行的,让我们看看下面的一些例子。

例如,S = “caba”, S' = “abac”;

S 以及S′之间的最长公共子串为“aba”,恰恰是答案。

尝试一下这个例子:S= “abacdfgdcaba”,
                S' = “abacdgfdcaba”;
S 以及 S′之间的最长公共子串为 “abacd” “abacd”,显然,这不是回文。

当 S 的其他部分中存在非回文子串的反向副本时,最长公共子串法就会失败。为了纠正这一点,每当我们找到最长的公共子串的候选项时,都需要检查子串的索引是否与反向子串的原始索引相同。如果相同,那么我们尝试更新目前为止找到的最长回文子串;如果不是,我们就跳过这个候选项并继续寻找下一个候选。

这给我们提供了一个复杂度为 O(n^2) 动态规划解法,它将占用 O(n^2)的空间(可以改进为使用 O(n) 的空间)。

思路二 (动态规划)

为了改进暴力法,我们首先观察如何避免在验证回文时进行不必要的重复计算。考虑“ababa” 这个示例。如果我们已经知道“bab”是回文,那么很明显,“ababa”一定是回文,因为它的左首字母和右尾字母是相同的。

我们给出 P(i,j)P(i,j) 的定义如下:

如果子串是回文子串其他情况
f ( i , j ) = { t r u e 如果子串Si...Sj是回文子串 f a l s e 其他情况 f(i,j)= \begin{cases} true& \text{如果子串Si...Sj是回文子串}\\ false& \text{其他情况} \end{cases}

因此,

P(i,j) = (P(i+1,j-1) and S_i==S_j)

基本示例如下:

P(i,j) = true; 

P(i,i+1) = (S_i == S_i+_1)

这产生了一个直观的动态规划解法,我们首先初始化一字母和二字母的回文,然后找到所有三字母回文,并依此类推…

复杂度分析

时间复杂度:O(n^2),这里给出我们的运行时间复杂度为 O(n^2)

空间复杂度:O(n^2),该方法使用O(n^2)的空间来存储表。

具体代码

class Solution {
public:
    string longestPalindrome(string s) {
        if(s.empty()) return s;
        int dp[s.size()][s.size()] = {0};
        int left = 0,right = 0,len = 0;
        for(int i=0;i<s.size();++i){
            for(int j=0;j<i;++j){
                dp[j][i] = (s[i] == s[j] && (i-j<2) || dp[j+1][i-1]);
                if(dp[j][i] && len < i-j+1){
                    len = i-j+1;
                    left = j;
                    right = i;
                }
            }
            dp[i][i] = 1;
        }
        return s.substr(left,right-left+1);
    }
};

猜你喜欢

转载自blog.csdn.net/qq_39478237/article/details/89457230