leetcode [5. 最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/)

leetcode 5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

提示:

  • 1 <= s.length <= 1000

  • s 仅由数字和英文字母组成

Related Topics

字符串

动态规划

思路1: 动态规划

参考leetcode:

分析:

对于一个长度大于2的字符串而言,如果去掉首尾的字符,它仍然是回文串,那么只要首尾字符相等,这个字符就是回文串。

我们可以使用二维数组来表示字符串i到j([i,j])是否为回文串。

  • P(i,j) 表示字符串i到j的位置是否为回文串。那么 P(i,j) = p(i+1,j-1) + (字符i等于字符j)

    • 想要求出i到j是否为回文串, 那么必须先求出i+1到j-1,所以我们必须求出长度从1到length的字串是否为回文串。

  • 特殊情况:

    • 当i=j,也就是一个字符的子串时,那么它就是回文串。

    • 当j=i+1时,此时P(i,j) = 字符i等于字符j,无需判断P(i-1,j-1)

  • 只需要保存最长回文串的起始位置和最大长度即可。

public String longestPalindrome(String s) {
   int length = s.length();
   boolean[][] dp = new boolean[length][length];
   int begin = 0;
   int maxLen = 1;
   char[] arrays = s.toCharArray();
   //子串的长度为size  需要判断每一个子串是否是回文串
   for(int size = 1; size <= length;size++){
       //判断以i为起点 长度为size的子串 终点为 i+size - 1
       for(int i = 0; i + size -1 < length;i++ ){
           //计算子串的终点位置
           int j = i + size -1;
​
           if(arrays[i] == arrays[j]){
               //特殊情况
                if(size <= 2){
                    dp[i][j] = true;
                }else{ //正常情况 Si == Sj && dp[i+1,j-1]
                    dp[i][j] = dp[i+1][j-1];
                }
           }else{
               dp[i][j] = false;
           }
​
           //如果是回文串 并且大于最大长度 更新begin和maxLen
           if(dp[i][j] && size > maxLen){
               begin = i;
               maxLen = size;
           }
       }
   }
   return s.substring(begin,begin+maxLen);
}
解答成功:
            执行耗时:167 ms,击败了40.87% 的Java用户
            内存消耗:44.7 MB,击败了14.36% 的Java用户

思路2:中心扩展算法

在思路1:边界是子串长度为1或者为2的情况。我们可以从这2种情况开始向外扩展,因为P(i,j) = P(i+1,,j-1),当P(i,j)不成立时,那么所有以P(i,j)为中心的子串都不会是回文串,就不需要判断了。

class Solution {
    public String longestPalindrome(String s) {
        int begin = 0;
        int maxLen = 1;
        int length = s.length();
​
        int len1,len2,len;
        for(int i = 0 ; i < length;i++){
            len1 = expandCenter(s,i,i);//长度为1的边界情况
            len2 = expandCenter(s,i,i+1);//长度为2的边界情况
            len = Math.max(len1,len2);
            //计算起始位置
            //举例:长度为1的边界情况向外扩展的长度为奇数  abcba 那么a的起始位置 2- 5/2( 5/2和4/2结果相等)
            //长度为2的边界情况向外扩展为偶数             bccb 那么b的起始位置 1-(4-1)/2
            //所以我们可以统计起始位置为 begin = i - (len-1)/2
            if(len > maxLen){
                begin = i - ((len-1)>>1);
                maxLen = len;
            }
        }
        return s.substring(begin,begin+maxLen);
    }
​
    /**
     * 以left到right为中心,向外扩展
     * @param s
     * @param left
     * @param right
     * @return
     */
    public int expandCenter(String s,int left,int right){
        while(left>=0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        //当退出循环后 是回文串的区间是[left+1,right-1]
        //[a,b]范围内的字符长度为b-a+1 ,所以上述为right-1-(left+1)+1 = right - left - 1
        return right - left - 1;
    }
}

思路3:Manacher 算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值