Loading...

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

题解

中心扩散法

/**
 * bacabab
 * 枚举每一个字符,到达 c 时,校验 bacab
 */
class Solution {
    public String longestPalindrome(String s) {
        int length = s.length();
        char[] array = s.toCharArray();
        String result = s.substring(0, 1);
        // 枚举每一个字符,每一个字符都为中间点
        for (int i = 0; i < length - 1; i++){
            // 找出当前最长的回文子串,列如 aba
            String p1 = isPalindrome(i, i, array, s);
            if (result.length() < p1.length()){
                result  = p1;
            }
            // 找出当前最长的回文子串,列如 abba
            String p2 = isPalindrome(i, i + 1, array, s);
            if (result.length() < p2.length()){
                result  = p2;
            }
        }
        return result;
    }
    private String isPalindrome(int left, int right, char[] array, String s) {
        // 当越界时,结束
        while (left >= 0 && right < array.length){
            // 如果当前左字符与右字符不等时,返回当前回文子串
            if (array[left] != array[right]) return s.substring(left + 1, right);
            left--;
            right++;
        }
        // 返回最长的回文子串
        return s.substring(left + 1, right);
    }
}

优化

/**
 * 中心扩散法
 */
public class Solution {
    public String longestPalindrome(String s) {
        int length = s.length();
        char[] array = s.toCharArray();
        int start = 0, end = 0;
        // 枚举每一个字符,每一个字符都为中间点
        for (int i = 0; i < length - 1; i++) {
            int len1 = expandAroundCenter(array, i, i);
            int len2 = expandAroundCenter(array, i, i + 1);
            int len = Math.max(len1, len2);
            if (len > end - start){
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end + 1);
    }
    public int expandAroundCenter(char[] array, int left, int right) {
        while (left >= 0 && right < array.length && array[left] == array[right]){
            left--;
            right++;
        }
        return right - left - 1;
    }
}

动态规划

/**
 * 动态规划
 */
class Solution {
    public String longestPalindrome(String s) {
        int length = s.length();
        char[] array = s.toCharArray();
        //dp [i][j] 表示 s [i..j] 是否是回文串
        boolean[][] dp = new boolean[length][length];
        // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < length; i++){
            for (int  j = 0; j < length; j++) {
                dp[i][j] = true;
            }
        }
        int maxLength = 1;
        int start = 0;
        // 先枚举子串长度
        for (int l = 2; l <= length; l++){
            // 枚举左边界,左边界的上限设置可以宽松一些
            for (int i = 0; i < length; i++){
                // 由 l 和 i 可以确定右边界,即 j - i + 1 = l 得
                int j = l + i - 1;
                // 如果右边界越界,就可以退出当前循环
                if (j >= length) break;
                if (array[i] != array[j]){
                    dp[i][j] = false;
                }else if (j - i < 3){
                    dp[i][j] = true;
                }else {
                    dp[i][j] = dp[i + 1][j - 1];
                }
                // 只要 dp [i][L] == true 成立,就表示子串 s [i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLength){
                    maxLength = j - i + 1;
                    start = i;
                }
            }
        }
        return s.substring(start, start + maxLength);
    }
}

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-palindromic-substring