最长回文子序列题解 递归+动态规划

从直接递归入手改为动态规划(官方的动态转移方程答案看不懂)

当某个字符串是回文序列时,考虑其内部字符串是否还是回文序列,可以看到每次遍历时的步骤是一致的,可以通过递归的方式求解

直接递归求解(此代码题解超时)

public static int process(char[] strArr,int l,int r){
        //base case
        //当只剩余一个字符时
        if(l==r){
            return 1;
        }
        //当只剩余2个字符时
        if(l==r-1){
            return strArr[l]==strArr[r]?2:1;
        }

        //any 考虑结尾情况分类
        //a.最终的最长回文子序列不以l r结尾
        //需要去考虑下一个位置
        int p1=process(strArr,l+1,r-1);

        //b.最终结尾以l结尾  不以r结尾
        //r位置向下偏移 考虑有可能产生回文的情况
        int p2=process(strArr,l,r-1);

        //c.最终结尾以r结尾  不以l结尾
        //l位置向内偏移 考虑下一个有可能产生回文的情况
        int p3=process(strArr,l+1,r);

        //d.均以l r结尾
        //判断当前位置是否可能产生结果
        //l r位置均往内偏移  寻找下一个可能产生回文的情况
        int p4= strArr[l]==strArr[r]? (2+process(strArr,l+1,r-1)):0;

        //收集以上4种情况取最大值
        return Math.max(Math.max(p1,p2),Math.max(p3,p4));
    }

改为递归

从递归过程很明显看到有2个变量l和r,故

  1. 构建二维dp表,大小为N*N

    int[][] dp=new int[N][N];
    
  2. base case

    根据递归步骤 dp表对角线上的格子都=1,对角线斜向右上方的斜线值也可以得到

    dp[i][i]=1;
    dp[i][i+1]=str[i]==str[i+1]?2:1;
    
  3. 确定返回值

    return dp[0][N-1];
    
  4. 一般性位置填表

    确定填表顺序。根据递归过程可以看到

    dp[i][j]位置依赖于 dp[i+1][j-1]   dp[i][j-1]   dp[i+1][j]
    

    所有一般性位置(i,j)依赖于左下角的位置,所有填表顺序为从下往上,从左往右

    public static int processDP(char[] strArr) {
            //1.构建dp表
            int N=strArr.length;
            int[][] dp=new int[N][N]; //[l,r]
    
            //2.base case
            for(int i=0;i<N;i++){
                dp[i][i]=1;
            }
    
            for(int i=0;i<N-1;i++){
                dp[i][i+1]= strArr[i]==strArr[i+1]?2:1;
            }
    
            //4.填表
            //确定顺序
            for(int i=N-3;i>=0;i--){
                for(int j=i+2;j<N;j++){
                    int p1=dp[i+1][j-1];
                    int p2=dp[i][j-1];
                    int p3=dp[i+1][j];
                    int p4= strArr[i]==strArr[j]? (2+dp[i+1][j-1]):0;
                    dp[i][j]=Math.max(Math.max(p1,p2),Math.max(p3,p4));;
                }
            }
    
            //3.返回值
            return dp[0][N-1];
        }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值