给出一个字符串str,返回这个字符串的最长回文子序列长度

问题描述:

给出一个字符串str,返回这个字符串的最长回文子序列长度;比如:str = "a123b321c"

最长回文子序列是123b321,返回长度是7

解决方案:从暴力递归到动态规划演变,三种方案如下

1、暴力递归:

public class NanDaoPalindromeSum {
    public static void main(String[] args) {
        String s = "a123b321c";
        System.out.println(palindrome1(s));
    
    }
   

    /**
     * 暴力递归
     * @param s
     * @return
     */
    private static int palindrome1(String s) {
        if(s == null || s.length() == 0){
            return 0;
        }
        char[] str = s.toCharArray();
        return p1(str,0,str.length - 1);
    }

    private static int p1(char[] str, int L, int R) {
        if(L == R){
            return 1;
        }
        if(L == R - 1){
            return str[L] == str[R] ? 2:1;//相等是2,不等是1
        }
        int p1 = p1(str,L + 1,R - 1);
        int p2 = p1(str,L,R - 1);
        int p3 = p1(str,L + 1,R);
        int p4 = str[L] == str[R] ? (2 + p1(str,L + 1,R - 1)) : 0;
       // System.out.println("p1:"+p1+";P2:"+p2+";P3:"+p3+";P4:"+p4);
        return Math.max(Math.max(p1,p2),Math.max(p4,p3));//返回最大值
    }

}

2、暴力递归到动态规划的过渡阶段:

2.1、图示分析:

给出的字符串 String s = "a123b321c";   长度为 9 ;行是L,列是R,L<=R;当L==R时,对角线赋值1,挨着对角线问号(?)赋值为1或2(R 和R+1相等为2),右上角为最终返回值

2.2、核心代码:

public class NanDaoPalindromeSum {
    public static void main(String[] args) {
        String s = "a123b321c";
 
        System.out.println(palindrome2(s));
   
    }
  
    /**
     * 暴力递归到动态规划的过渡阶段
     * @param s
     * @return
     */
    private static int palindrome2(String s) {
        if(s == null || s.length() == 0){
            return 0;
        }
        char[] str = s.toCharArray();
        int N = str.length;
        int[][] dp = new int[N][N];
        dp[N - 1][N - 1] = 1;
        for(int i = 1;i < N - 1;i++){
            dp[i][i] = 1;
            dp[i][i + 1] = str[i] == str[i + 1] ? 2 : 1;//相等是2,不等是1
        }
        for(int L = N - 3;L >= 0;L--){
            for(int R = L + 2;R < N;R++){
                int p1 = dp[L + 1][R - 1];
                int p2 = dp[L][R - 1];
                int p3 = dp[L + 1][R];
                int p4 = str[L] == str[R] ? (2 + dp[L + 1][R - 1]) : 0;
                dp[L][R] =  Math.max(Math.max(p1,p2),Math.max(p3,p4));
            }
        }
        return dp[0][N - 1];
    }


}

3、标准的动态规划方案:

3.1、继续分析上图:某个格子位置是其左边和下边取最大值得到的,即6位置是从5和3位置中取最大值得到的,肯定不是其左下(2位置)的值,因此可以继续优化代码;

3.2、核心代码如下:

public class NanDaoPalindromeSum {
    public static void main(String[] args) {
        String s = "a123b321c";
      
        System.out.println(palindrome3(s));
    }
    /**
     * 动态规划
     * @param s
     * @return
     */
    private static int palindrome3(String s) {
        if(s == null || s.length() == 0){
            return 0;
        }
        char[] str = s.toCharArray();
        int N = str.length;
        int[][] dp = new int[N][N];
        dp[N - 1][N - 1] = 1;
        for(int i = 0;i < N - 1;i++){
            dp[i][i] = 1;//对角线赋值为1
            dp[i][i + 1] = str[i] == str[i + 1] ? 2 : 1;//对角线上面一层赋值,相等是2,不等是1
        }

        for(int L = N - 3;L >= 0;L--){
            for(int R = L + 2;R < N;R++){
                dp[L][R] = Math.max(dp[L][R - 1],dp[L + 1][R]);//左和下左对比
                if(str[L] == str[R]){//如果相等,继续往左下角遍历
                    dp[L][R] = Math.max(dp[L][R],(2 + dp[L + 1][R - 1]));
                }
            }
        }
        return dp[0][N - 1];
    }

}

3.3、三种方案的执行结果:

4、三种方案的基本思想如下:

4.1、从上到下,从左到右,每个格子里的值就是需要返回的值,因此取最大值返回即可。

4.2、从尝试该动态规划,只需要把位置找对就行。

到此,该算法分享完毕,大家一定要多多练习,勤于思考,早日成为大牛!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值