LeetCode第五题(最长回文子串)

185 阅读1分钟

暴力解法(Java)

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }
        int maxLen = 1;
        int begin = 0;
        char[] charArray = s.toCharArray();
        // 枚举所有长度大于 1 的子串 charArray[i..j]
        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) {
                if (j - i + 1 > maxLen && validPalindromic(charArray, i, j)) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }

    //验证子串 s[left..right] 是否为回文串
    private boolean validPalindromic(char[] charArray, int left, int right) {
        while (left < right) {
            if (charArray[left] != charArray[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

动态规划解法(Java)

62fd64a7088ca9621dea933a515ad0f.png

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();//字符串s的长度
        int maxLen = 1;//最长的回文子串的长度
        int begin = 0;//最长的回文子串的左边界
        char[] charArray = s.toCharArray();//字符串转为字符数组,便于判断回文串
        boolean[][] dp = new boolean[len][len];//dp[i][j]表示s[i..j]是否回文串
        //字符串长度为1都是回文串(题目规定1 <= s.length <= 1000,故下述for可省略)
        for(int i = 0; i < len; i++)
            dp[i][i] = true;
        for(int L = 2; L <= len; L++){
            //回文子串的左边界
            for(int i = 0; i < len; i++){
                int j = L + i - 1;//回文子串的右边界
                if(j >= len)//右边界超出字符串长度
                    break;
                if(charArray[i] != charArray[j])//首尾字符不同
                    dp[i][j] = false;
                else{//首尾字符相同
                    if((j - i) < 3)//子串长度为2或3时,首尾字符相同必为回文串
                        dp[i][j] = true;
                    else//P(i,j)=P(i+1,j−1)
                        dp[i][j] = dp[i + 1][j - 1];
                }
                //s[i..j]是回文串且长度更长
                if(dp[i][j] && (j - i + 1) > maxLen){
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }
}

中心扩散解法(Java)

核心思想:回文串的中心只有两种情况,其一是中间只有一个字符,其二是中间有两个相同字符,在此基础上向边界扩散,只要扩散边界的两个字符不相同,则该字符串不是回文串(注意边界的越界判断)。

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();//字符串s的长度
        int start = 0, end = 0;//回文子串的边界
        for(int i = 0; i < len; i++){
            int len1 = extend(s, i, i);//中间只有一个字符
            int len2 = extend(s, i, i + 1);//中间有两个相同字符
            int maxLen = Math.max(len1, len2);//取其较大长度
            //子串长度更长
            if(maxLen > (end - start + 1)){
                start = i - (maxLen - 1) / 2;//定位最长回文子串的左边界
                end = i + maxLen / 2;//定位最长回文子串的右边界
            }
        }
        return s.substring(start, end + 1);
    }  
    
    //由回文串的中心向边界扩散 
    public int extend(String s, int left, int right){
        //扩散条件:左边界不越界且右边界不越界且左、右边界的字符相同
        while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        return right - left - 1;//计算当前回文子串的长度
    }
}