【刷题篇】最长回文子序列

一、题目

OJ链接

二、题解

2.1 方法一 :求该字符串与它的逆序字符串的最长公共子序列

一个字符串的最长回文序列就是:
该字符串与它的逆序字符串的最长公共子序列
因为我们之前写过求两个字符串的最长公共子序列的题目
在这里插入图片描述

具体可见:

最长公共子序列

2.2 方法二:暴力递归

应用范围尝试模型解题(讨论一个范围的开头和结尾的可能性)

递归函数
在这里插入图片描述
递归函数的含义:只考虑字符串str,从L到R位置的最长回文子序列的长度
终止条件

L== R时,只剩下一个字符,一个字符是回文序列,长度是1,return 1; L==
R-1时,说明只剩下两个字符,如果这两个字符串相等,则构成回文序列,长度是2,如果不相等,最长的回文子序列长度就是1;

普遍情况:

考虑str[L…R]这个范围上最长回文子序列的可能性 (1)最长回文子序列既不以L开头,也不以R结尾
(2)最长回文子序列以L开头,不以R结尾 (3)最长回文子序列不以L开头,但以R结尾 (4)最长回文子序列以L开头,以R结尾

既然递归函数的含义是求L到R范围上的最长回文子序列长度,那么主函数上就应该这样调用
在这里插入图片描述
源码:
👯

public static int f1(char[] str,int L,int R){
    if(L==R){
        return 1;
    }
    if(L==R-1){
        return str[L]==str[R-1]?2:1;
    }
    int p1=f1(str,L+1,R-1);
    int p2=f1(str, L+1, R);
    int p3=f1(str,L,R-1);
    int p4=str[L]==str[R]?2+f1(str, L+1, R-1):0;
    return  Math.max(Math.max(p1,p2),Math.max(p3,p4));
}
    public static int longestPalindromeSubseq1(String s) {
        if(s==null||s.length()==0){
            return 0;
        }
       char[] str=s.toCharArray();
        return f1(str,0,str.length-1);
    }

2.3 方法三:动态规划

思路:
根据方法二中的递归函数填表格
在这里插入图片描述
源码:

 public static int longestPalindromeSubseq2(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;
            dp[i][i+1]=str[i]==str[i+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+1][R]; 
                int p3=dp[L][R-1];
                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];
    }

优化:对方法法优化
在这里插入图片描述

  public static int longestPalindromeSubseq2(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;
            dp[i][i+1]=str[i]==str[i+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+1][R];
                int p3=dp[L][R-1];
                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];
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值