Skip to content

Latest commit

 

History

History
107 lines (91 loc) · 3.81 KB

5.最长回文子串.md

File metadata and controls

107 lines (91 loc) · 3.81 KB

5 最长回文子串

题目

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

示例 1:

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


示例 2:

输入: "cbbd"
输出: "bb"

方法一(动态规划)

一个长度大于2的回文串,去掉首尾两个字母后仍然是一个回文串。 用dp[i][j]表示字符串s的第i到j个字母组成的串是否为回文串。即有动态规划状态转移方程

dp[i][j] = dp[i+1][j-1] && s.charAt(i) == s.charAt(j)

意为:如果从i+1到j-1的一个子串是回文串,并且s[i]和s[j]相等,则从i到j的子串也是回文串
接下来考虑边界条件:(回文串长度小于等于2时)

  • s长度为1:肯定为回文串
  • s长度为2:判断s[i]和s[j]是否相等

由于在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,所以要先遍历j,再遍历i。在遍历的过程中不断更新max_len,即可获得最长回文子串长度j-i+1和起始位置start。

代码:

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length() < 1)
            return "";
        int length = s.length();
        //dp[i][j]表示字符串s的第i到j个字母组成的串是否为回文串
        boolean[][] dp = new boolean[length][length];
        int start = 0;
        //max_len记录最长回文子串的长度
        int max_len = 1;
        for(int j = 0; j < length; j++){
            for(int i = 0; i < length; i++){
                //i必须小于j,因此当i大于j时可以直接continue跳过不处理
                if(i > j)
                    continue;
                //长度为1的子串肯定是回文串
                if(i == j)
                    dp[i][j] = true;
                //子串长度为2并且i和j对应的字符相等时,为回文字符串
                if(j == i + 1){
                    dp[i][j] = s.charAt(i) == s.charAt(j);
                }
                //子串长度大于2时,依据动态规划的状态转移方程判断
                if(j - i > 1){
                    dp[i][j] = dp[i+1][j-1] && s.charAt(i) == s.charAt(j);
                }
                //更新回文子串的最长长度max_len以及这个子串的起始位置start
                if(dp[i][j] && j-i+1 > max_len){
                    max_len = j-i+1;
                    start = i;
                } 
            }
        }
        String res = new String(s.toCharArray(), start, max_len);
        return res;

    }
}

注:方法toCharArray()将s转换为一个字符数组,该字符数组中存放了当前字符串中的所有char类型字符。

方法二(中心扩展法)

字符串s可能有2N - 1个可能的中心,其中:

  • 每个单字符都可能作为中心扩展出长度为奇数的回文串,这种情况有N种。
  • 每一对相邻的双字符也可能作为中心扩展出长度为偶数的回文串,这种情况有N - 1种

对每一个中心都尽可能地尝试向外扩展,找到能扩出的最长长度以及其对应的最长回文串

public String longestPalindrome(String s) {
    if(s == null || s.length() == 0)
        return "";
    int maxLen = 0;
    int res_left = 0;
    int res_right = 0;
    for(int i = 0; i < 2 * s.length() - 1; i++){
        int left = i / 2;
        int right = i / 2 + i % 2;
        while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        int len = right - left - 1;
        if(len > maxLen){
            maxLen = len;
            res_left = left + 1;
            res_right = right - 1;
        }
    }
    return s.substring(res_left, res_right + 1);
}