手撕算法—— 最长回文子串

题目描述

最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: “babad”
输出: “bab”

注意: “aba” 也是一个有效答案。
示例 2:

输入: “cbbd”
输出: “bb”

解题思路

看到这道题的时候,第一眼能想到的方法就是暴力破解,枚举每个子串,看它是不是回文子串,并且记录最长的回文子串。它的时间复杂度为O(N^3),空间复杂度为O(N),这里N指的是数组的长度。
时间复杂度为O(N^3)的原因是使用两层for循环找到所有的子串,然后再使用一层for循环判断该子串是否为回文子串。这里我们不讨论它的实现。

接下来我们讨论如何使用动态规划解决这个问题。

动态规划解题模板

动态规划解题是有章可循的,我们可以将其分为以下五步:
(1)确定dp数组元素的含义
(2)确定状态转移方程
(3)确定初始值
(4)根据初始值和状态转移方程确定dp数组元素的值
(5)考虑空间压缩

我们直接结合代码来分析:
第一步:确定dp数组元素的含义

  • 对于最长回文子串我们可以定义数组dp[i][j]表示区间[i,j]是否为回文子串。

第二步:确定状态转移方程

  • 如果 s[i]!=s[j] ,将dp[i][j]置为false;
  • 如果 s[i]==s[j],并且dp[i+1][j-1]==true,我们则将dp[i][j]置为true;
  • 考虑特殊情况如 “aa”, “aba” ,当s[i]==s[j]的时候可以直接将其置为true,因此可以得到 s[i]==s[j]&&j-i<3时 dp[i][j]=true;

第三步:确定初始值

  • 每一个元素都为一个回文子串,因此对于 0<i<s.length(),dp[i][i]=true;

第四步:根据初始值和状态方程确定数组元素的值

  • 这里使用两层for循环将确定每个子串是否为回文。

第五步:考虑空间压缩

代码实现
class Solution {
    public String longestPalindrome(String s) {
        //判非
        if(s==null||s.length()<=1){
            return s;
        }
        
        int len=s.length();
        char[] arr=s.toCharArray();

		//确定数组元素含义
        boolean dp[][]=new boolean[len][len];

        //初始化
        for(int i=0;i<len;i++){
            dp[i][i]=true;
        }
     
        int maxLen=1;//记录最大回文子串的长度
        int start=0;//记录最大回文串的起始坐标
		
		//根据初始值和状态方程确定数组元素的值
        for(int j=1;j<len;j++){
            for(int i=0;i<j;i++){
                        if(arr[i]==arr[j]){
                            if(j-i<3||dp[i+1][j-1]){
                            dp[i][j]=true;
                            int l=j-i+1;
                            if(maxLen<l){//判断长度
                                start=i;
                                maxLen=l;
                            } 
                        }
                    }else{
                        dp[i][j]=false;
                    }
            }
        }
        return s.substring(start,start+maxLen);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值