力扣周末回顾6 - 5题 最长回文子串

力扣周末回顾题6

题目出处:点击此处

考点:动态规划,字符串,回文,中心扩散法(本博文不涉及)

回顾:
动态规划五要素:
1.判断状态是否转移(是否能用dp数组表示?)
2.状态转移方程表示(dp数组的判断,相当于分类讨论)
3.初始化(考虑边界)
4.输出(验证结果)
5.压缩,优化。

题解:

1.找到最长的回文子串
(注意三个个限定:最长,回文,子串)
考虑到肯定设计到穷举+剪枝,必定可以用状态转移。

————————————————————————————————

2.状态DP【i】【j】代表字符串以i开头,j结尾的字符串是否是回文。

那么如何判定一个字符串是回文呢?

如果 i == j ,并且dp【i+1】【j-1】也是回文则说明DP【i】【j】就是回文。
(这个条件要发现真的不简单,发现不了的读者要多归纳总结)

—————————————————————————————————
特殊边界情况:

我们可以知道,当满足 i == j 之后,有些值是不需要判断【i-1】【j-1】,直接可以知道是回文的,条件即:

j - i < 3;

相当于字符串只有一个或两个字符。

—————————————————————————————————
3.初始化

全部置为false,没啥好说的。

————————————————————————————————
4.输出

这里要注意了,我们这次要得不是DP【length-1】【length-1】,而是记录

在过程中最大长度,并记录起始的字符位置。

这里是未经优化的版本:
时间复杂度O(n2),空间复杂度O(n2);
执行用时:136 ms。

class Solution {
    public String longestPalindrome(String s) {
        char[] characterlist = s.toCharArray();
        int length = characterlist.length;
        // 特殊情况
        if(length == 0){
            return "";
        }
        boolean[][] dptable = new boolean[length][length];
        // 初始化
        for(int i = 0;i<length;i++){
            for(int j = 0; j<length;j++){
                dptable[i][j] = false;
            }
        }
        int maxlen = 0;
        int maxstart = 0;
        // 一列一列进行dp计算
        for(int j = 0; j< length; j++){
            for(int i = 0; i<length; i++){
                // 行不能大于列
                if(i > j){
                    break;
                }
                // 左右相等
                if(characterlist[i] == characterlist[j]){
                    // 边界条件,无条件置为正确;
                    if( j - i < 3){
                        dptable[i][j] = true;
                        // 记录最长的字符串
                        if(j-i+1 > maxlen){
                            maxlen = j - i + 1;
                            maxstart = i;
                        }
                        continue;
                    }
                    // 内部也是回文
                    if(dptable[i+1][j-1] == true){
                        dptable[i][j] = true;
                        // 记录最长的字符串
                        if(j-i+1 > maxlen){
                            maxlen = j - i + 1;
                            maxstart = i;
                        }
                        continue;
                    }
                }
                dptable[i][j] = false;
            }
        }
    return s.substring(maxstart,maxstart+maxlen);
    }
}

5.压缩,优化。

经过打表,我们可以发现,从始至终这个dp表都是只有一列在依照上一列进
行更新。于是我们可以压缩为一列。

优化后:
时间复杂度O(n2),空间复杂度O(n);
执行用时:37ms。

class Solution {
    public String longestPalindrome(String s) {
        char[] characterlist = s.toCharArray();
        int length = characterlist.length;
        // 特殊情况
        if(length == 0){
            return "";
        }
        boolean[] dptable = new boolean[length];
        // 初始化
        for(int i = 0;i<length;i++){
            dptable[i] = false;
        }
        int maxlen = 0;
        int maxstart = 0;
        // 一列一列进行dp计算
        for(int j = 0; j< length; j++){
            for(int i = 0; i<length; i++){
                // 行不能大于列
                if(i > j){
                    break;
                }
                // 左右相等
                if(characterlist[i] == characterlist[j]){
                    // 边界条件,无条件置为正确;
                    if( j - i < 3){
                        dptable[i] = true;
                        // 记录最长的字符串
                        if(j-i+1 > maxlen){
                            maxlen = j - i + 1;
                            maxstart = i;
                        }
                        continue;
                    }
                    // 内部也是回文
                    if(dptable[i+1] == true){
                        dptable[i] = true;
                        // 记录最长的字符串
                        if(j-i+1 > maxlen){
                            maxlen = j - i + 1;
                            maxstart = i;
                        }
                        continue;
                    }
                }
                dptable[i] = false;
            }
        }
    return s.substring(maxstart,maxstart+maxlen);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值