LeetCode 5 最长回文子串

LeetCode 5 最长回文子串

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

动态规划

执行用时:209 ms, 在所有 Java 提交中击败了12.42%的用户
内存消耗:50.1 MB, 在所有 Java 提交中击败了5.01%的用户

class Solution{
    //动态规划
    //dp[i][j]表示str[i, j]范围内最长回文子串长度, j>=i
    //dp[i][j]与dp[i+1][j]、dp[i][j-1]、dp[i+1][j-1]有关
    //1. 若str[i]==str[j] and dp[i+1][j-1]==j-(i+1)
    //      dp[i][j] = dp[i+1][j-1]+2
    //2. 其它情况
    //      dp[i][j] = max{dp[i+1][j], dp[i][j-1], dp[i+1][j-1]}
    //初始: dp[i][i] = 1
    public String longestPalindrome(String s) {
        if(s==null || s.length()<=1) {
            return s;
        }

        int[][] dp = new int[s.length()][s.length()];
        //状态初始化
        for(int i=0; i<s.length(); i++) {
            dp[i][i] = 1;
        }
        //状态递推O(N2)
        int left = 0, right = 0;
        //遍历方式存在问题(保证后有效性)
        for(int j=0; j<s.length(); j++) {
            for(int i=0; i<=j; i++) {
                if(i==j) {
                    continue;
                }
                //考虑奇对称、偶对称两种情况下的初始情况(两个值、三个值)
                if(s.charAt(i)==s.charAt(j) 
                && (i+1==j || dp[i+1][j-1]==(j-i-1))) {
                    dp[i][j] = j+1-i;
                }
                else {
                    dp[i][j] = Math.max(
                        i+1==j? 0: dp[i+1][j-1], 
                        Math.max(dp[i+1][j], dp[i][j-1])
                    );
                }
                //记录字符串起始坐标
                if(right+1-left < dp[i][j] && dp[i][j]==j+1-i) {
                    left = i;
                    right = j;
                }
            }
        }
        return s.substring(left, right+1);
    }
}

暴力优化: 中心扩散

执行用时:58 ms, 在所有 Java 提交中击败了59.81%的用户
内存消耗:37.6 MB, 在所有 Java 提交中击败了67.40%的用户

//问题描述:在给定字符串中找到最长的回文“子串”,回文子串的定义为:字符串对称分布,即从左到右、从右到左遍历输出一致
/**动态规划:
 * 状态转移:Sub[i,j]表示arr[i]..arr[j]组成的子串
 *          若Sub[i,j]是回文串,则需要满足:Sub[i+1,j-1]是回文串,且arr[i] == arr[j]
 * 递推:找到一个最小的回文串,例如"aa"、"aba",由该回文串向外扩展
 * */
 //O(N2/2)
class Solution{
    public String longestPalindrome(String s) {
        if(s.length()<=1) return s;
        if(s.length()==2) return (s.charAt(0)==s.charAt(1))?s:s.charAt(0)+"";

        int maxLen = 1, minLeft = 0, maxRight = 0;
        //1、找到一个最小的回文串(由第二个向倒数第二个寻找)
        //2、由最小回文串向两边扩展,找到一个最长的回文串
        //时间复杂度:O(N2)
        for(int i=1;i<s.length()-1;i++){
            //偶数
            if(s.charAt(i)==s.charAt(i-1)){
                int currLen = searchPalindrome(s, i-1, i);
                if(maxLen < currLen){
                    maxLen = currLen;
                    minLeft = i - currLen/2;
                    maxRight = i-1 + currLen/2;
                }
            }
            if(s.charAt(i) == s.charAt(i+1)){
                int currLen = searchPalindrome(s, i, i+1);
                if(maxLen < currLen){
                    maxLen = currLen;
                    minLeft = i+1 - currLen/2;
                    maxRight = i + currLen/2;
                }
            }
            //奇数
            if(s.charAt(i-1)==s.charAt(i+1)){
                int currLen = searchPalindrome(s, i-1, i+1);
                if(maxLen < currLen){
                    maxLen = currLen;
                    minLeft = i - currLen/2;
                    maxRight = i + currLen/2;
                }
            }
        }

        System.out.println("maxLen="+maxLen);
        return s.substring(minLeft, maxRight+1);
    }

    public int searchPalindrome(String s, int i, int j){
        int maxLen = j-i+1;
        i--;j++;
        while(i>=0 && j<s.length()){
            if(s.charAt(i) != s.charAt(j)) break;
            maxLen += 2;
            i--;j++;
        }
        return maxLen;
    }

}
posted @ 2020-09-18 21:30  CodeSPA  阅读(123)  评论(0编辑  收藏  举报