leetcode5最长回文子串:如何巧妙构建dp数组和状态转移

在这里插入图片描述

如何构造dp数组

一开始想到的是dp[i][j]表示索引i到索引j之间的最长回文子串,然后我们的目标是d[0][length-1];
基于此定义,如果要构造状态转移,会发现异常困难;
题解中采用的是dp[i][j]表示索引i到索引j之间的字符串是否为回文子串
即第一个的返回值为String,第二个的返回值为boolean
基于第二个定义,构造状态转移会非常容易
dp[i][j]=dp[i+1][j-1] && (st[i]==st[j])
即如果一个字符串本身为回文串,那么两边各加上相同的单个字符串,整体必然是回文串;
同时考虑base case
当i==j时,dp[i][j]=true;
当i+1==j时,dp[i][j]=true;
当j-i>=2时,就可以直接使用状态转移

class Solution {
    public String longestPalindrome(String s) {
        char[] st=s.toCharArray();
        int length=st.length;
        boolean[][] dp=new boolean[length][length];
        // base case赋值
        for(int i=0;i<length;i++) {
        	dp[i][i]=true;
        	if(i+1<length){
        		dp[i][i+1]=(st[i]==st[i+1]);
        	}
        	
        }
        //错误的遍历方式
//        for(int i=0;i<length;i++){
//            for(int j=i;j<length;j++){
//            	if(j-i>1) {
//            		dp[i][j]=dp[i+1][j-1]&&(st[i]==st[j]);
//            	}
//            	
//            }
//        }
		// 状态转移
        int tail=0;
        int front=0;
        for(int len=3;len<=length;len++) {
        	for(front =0;front<length;front++) {
        		tail=front+len-1;
        		if(tail>=length) {
        			break;
        		}
        		dp[front][tail]=dp[front+1][tail-1]&&(st[front]==st[tail]);
        	}
        }
        // 找到最大回文子串
        int max=0;
        for(int i=0;i<length;i++){
            for(int j=i;j<length;j++){
                if(dp[i][j]==true){
                    if(j-i>=max){//加上等于号防止进不去
                        max=j-i;
                        front=i;
                        tail=j;
                    }
                }
            }
        }
        // 将其截取
        String out="";
        for(int i=front;i<=tail;i++){
            out=out+st[i];
        }
        return out;
    }
}

一开始我用的遍历是i和j都用for循环,其中i从0开始,j从i开始
但这样有问题
比如dp[0][5]需要用到dp[1][4]
而算到前者时,后者还未算到,所以如果按初始值false来算就会出错
因此这样的遍历方式是有问题的

基于以上问题
正确的遍历方式是先考虑短的子串,再逐渐将其加长;
外循环用子串长度作为变量
内循环用左索引作为变量
最后dp数组都赋值结束之后,就可以从值为true的元素中找出长度最长的子串

总结

本题中的dp数组的构造非常巧妙
不直接求出回文子串
而是判断是否为回文子串

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值