LeetCode 5. 最长回文子串

这篇博客介绍了如何解决字符串中最长回文子串的问题,提供了三种不同的方法:暴力法、动态规划和中心扩散法。动态规划方法通过状态转移方程有效地减少了时间复杂度,而中心扩散法则从字符串的中心开始向外扩散寻找回文子串。文章通过示例代码详细解释了每种方法的实现细节,并给出了具体的运行例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5. 最长回文子串

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

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"
  1. 暴力法(超时)
class Solution {
    public String longestPalindrome(String s) {
       String res = new String();
       int max = 0;
       for(int i = 0;i<s.length();i++){
           //substring(i,j); [i,j) 左闭右开区间
         for(int j = i+1; j<=s.length();j++){
             //分割子字符串
             String temp = s.substring(i,j);
             //判断是否为回文子串  是赋值给res  并保存最长长度
             if(isPalidrome(temp)&&temp.length()>max){
                res = temp;
                max = Math.max(res.length(),max);
             }
         }
       }

       return res;
    }

    //判断是否为回文子串
    public static boolean isPalidrome(String arr){
        int len = arr.length();
        for(int i = 0 ;i<len/2;i++){
            //判断得到的字符串是否回文子串 不是 返回false  0与 length-1比较  1与length-1-1相比 以此类推
            if(arr.charAt(i)!=arr.charAt(len-1-i)){
                return false;
            }
        }
        return true;
    }
}
  1. 动态规划

    对于一个子串而言,如果它是回文串,并且长度大于 22,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串“ababa”,如果我们已经知道“bab” 是回文串,那么 “ababa” 一定是回文串,这是因为它的首尾两个字母都是 “a”。

    根据这样的思路,我们就可以用动态规划的方法解决本题。我们用 P(i,j)表示字符串 s 的第 i 到 j个字母组成的串(下文表示成 s[i:j])是否为回文串:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LlmsZIHY-1607434207089)(C:\Users\ADMINI~1\AppData\Local\Temp\1607429143204.png)]

    这里的「其它情况」包含两种可能性:

    • s[i, j]s[i,j] 本身不是一个回文串;

    • i > ji>j,此时 s[i, j]s[i,j] 本身不合法。

​ 那么我们就可以写出动态规划的状态转移方程:
P ( i , j ) = P ( i + 1 , j − 1 ) ∧ ( S i = = S j ) P(i, j) = P(i+1, j-1)∧(Si ==Sj) P(i,j)=P(i+1,j1)(Si==Sj)
​ 也就是说,只有 s[i+1:j-1]是回文串,并且 s 的第 i和 j个字母相同时,s[i:j]才会是回文串。

​ 对于特殊的情况

  • 当子串长度为1时,P(i,j) = true

  • 当子串长度为2时,
    P ( i , i + 1 ) = ( S i = = S i + 1 ) P(i,i+1) = (Si == Si+1) P(i,i+1)=(Si==Si+1)

图形说明

在这里插入图片描述

class Solution {
    //动态规划
    public String longestPalindrome(String s) {
    int n = s.length();
    String res="";
    boolean[][] dp = new boolean[n][n];
     for(int l=0;l<n;l++){
         //循环终止条件:i+l<n 循环只在对角线的斜上方的数据
         for(int i = 0;i+l<n;i++){
             //第一轮:dp[0][0] dp[1][1] dp[2][2] i与j相等   因为l=0
             //第二轮:dp[0][1] dp[1][2] dp[2][3] i与j差一位 因为l=1
             //第二轮:dp[0][2] dp[1][3] dp[2][4] i与j差两位 因为l=2 ......
             int j = i+l;
             if(l == 0){
                 //单个字符的情况
                dp[i][j] = true;
             }else if(l==1){
                 //临近两个字符是否相等的情况
                dp[i][j] = s.charAt(i) ==s.charAt(j);
             }else{
                 //其他情况
                dp[i][j] = (s.charAt(i) ==s.charAt(j))&&dp[i+1][j-1];
             }
             if(dp[i][j]&& l+1>res.length()){
                res= s.substring(i,i+l+1);
             }
         }
     }
    return res;
   }
}
  1. 中心扩散法

图 1 :奇数回文串与偶数回文串

class Solution {
    //动态规划
    public String longestPalindrome(String s) {
    int n = s.length();
    if(n<2) return s;
    String res="";
    int maxLength=0;
     for(int i=0;i<n-1;i++){
         String oddSearch = centerSpread(i,i,s);  //奇数个数情况
         String evenSearch = centerSpread(i,i+1,s); //偶数个数情况
         String tempRes = oddSearch.length()>evenSearch.length()?oddSearch:evenSearch;
         if(tempRes.length()>maxLength){
            maxLength = tempRes.length();
            res = tempRes;
         }
     }
    return res;
   }

   public static String centerSpread(int left,int right,String s){
         int i = left;
         int j = right;
         while(i>=0 &&j<s.length()){
             if(s.charAt(i) == s.charAt(j)){
                 //向外散开
                i--;
                j++;
             }else{
                 break;
             }
         }
         //因为最后一个i是不满足回文串的情况  所以要+1
         return s.substring(i+1,j);

   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值