leetcode5. 最长回文子串-动态规划详细解释无后效性

leetcode5. 最长回文子串


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

示例 1:

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

示例 2:
输入: “cbbd”
输出: “bb”

动态规划的思路

一般题里问什么就把什么设成dp。
在当前状态,假设前面的状态全部计算出来了,即无后效性,再去寻找动态规划方程。
dp [i][j]表示字符串i~j是不是回文字符串。
初始化:dp[i][i]肯定是回文的,因为只有一个字符。
当遍历到一个状态的时候,这个状态是不是回文取决于两个:

  • 字符 i 和字符 j 相等,也就是说字符串的首尾是一样的。
  • 去掉首尾,也就是 i+1~j-1 是回文字符串。
  • 字符串长度为2,也就是说去掉首尾就没了,类似于 “bb” 这种需要特殊判断。
    思路就绪了,开始写代码。

先看我的错误版本:

public String longestPalindrome(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];//i~j 是否为回文,并且长度是多少
        for (int i = 0; i < n; i++) {
            dp[i][i] = 1;
        }
        String ans = new String(s.toCharArray(), 0, 1);
        for (int i = 0; i < n; i++) {
            
            for (int j = i + 1; j < n; j++) {
                if (i + 1 == j && s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = 2;
                }
                if (dp[i + 1][j - 1] > 0 && s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } 
                
                if (dp[i][j] > ans.length()) {
                    ans = new String(s.toCharArray(), i, j - i + 1);//截取字符串
                }
                System.out.println("i = "+i+" j = "+j+" ans = "+ans+" dp[i][j] = "+dp[i][j]);
            }
            
        }
        return ans;
    }

乍一看不会出现问题,但是对于 “babab” ,结果是错误的,只能得到 “bab” 。来看原因。

把dp数组画出来

因为动态规划其实就是怎么填充dp数组,我们看看dp数组是怎么变化的。
初始状态:
在这里插入图片描述
这是在初始化之后的初始状态。
看看上面的代码是怎么填充dp数组的。
在这里插入图片描述
i=0,j=4 时,需要用到 dp[1][3] 。这是不对的,动态规划需要有无后效性,也就是说当前的状态不能用到之后的状态。
那么只能换一种填表方式。填表方式有很多,只要满足当前的状态不用到没填过的就行。我用的是下面这种。
在这里插入图片描述
这回就ok了,来看代码。优化了一部分,没必要每次截取,只需记录位置就行。

public String longestPalindrome(String s) {
     if (s.length() == 0) return s;
     int n = s.length();
     int[][] dp = new int[n][n];//i~j 是否为回文,并且长度是多少
     for (int i = 0; i < n; i++) {
         dp[i][i] = 1;
     }
     int left = 0;
     int right = 0;
     int max = 0;
     for (int i = n - 1; i >= 0; i--) {
         for (int j = n - 1; j > i; j--) {
             if (i + 1 == j && s.charAt(i) == s.charAt(j)) {
                 dp[i][j] = 2;
             }
             if (dp[i + 1][j - 1] > 0 && s.charAt(i) == s.charAt(j)) {
                 dp[i][j] = dp[i + 1][j - 1] + 2;
             } 
             
             if (dp[i][j] > max) {
                 max = dp[i][j];
                 left = i;
                 right = j;
             }
             //System.out.println("i = "+i+" j = "+j+" ans = "+ans+" dp[i][j] = "+dp[i][j]);
         }
         
     }
     return s.substring(left, right + 1);
 }

这回动态规划的理解更进一步了。
leetcode上面类似的字符串题:
字符串三连
最长回文子序列
回文子串
最长回文子串
leetcode 75/100

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值