5. 最长回文子串

115 阅读2分钟

最长回文子串

难度:中等

最长回文子串
参考

p1:通过中心向外扩充

//以每一个位置为中心向外扩散找最大子串
public String longestPalindrome(String s) {
    int length = s.length();
    int[] dp = new int[length];
    int maxlen = 0;
    String ans = "";

    for(int i = 0; i < length; i++){
    //因为中心可能有一个值或者两个值,要分情况
        int len1 = lenPalindrome(s, i, i);
        int len2 = lenPalindrome(s, i, i+1);
        int len = Math.max(len1, len2);
        if(maxlen < len){
            maxlen = Math.max(maxlen, len);
            ans = s.substring(i - (len-1)/2, i + len/2 + 1);
        }
       
    }
    return ans;
}
//判断以 start,end为中心的字符串向外扩展回文的最大长度
public static int lenPalindrome(String s, int start, int end){
    while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
        start--;
        end++;
    }
    return end - start - 1;
}

p2:动态规划

boolean保存[i,j]区间是否为回文

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

边界值(长度为1或2时要单独考虑)

public String longestPalindrome(String s){
    int length = s.length();
    //dp保存从[i,j]区间内是否为回文字符串
    boolean[][] dp = new boolean[length][length];
    int maxlen = 0;
    String ans = "";

    for(int len = 1; len <= length; len++){  //注意<= length
        for(int start = 0; start < length; start++){
            int end = start + len - 1;
            if(end >= length) break;
            dp[start][end] = (len == 1 || len == 2 || dp[start+1][end-1]) && s.charAt(start) == s.charAt(end);

            if(dp[start][end] && maxlen < len){
                maxlen = len;
                ans = s.substring(start, end+1);
            }
        }
    }
    return ans;
}

p3:将字符串反转,反转字符串和原字符串进行比较(最长公共子串),不过要注意(abcghjcba)此类字符串,所以每次比较要进行字符位置判断(反转后的公共字符位置与反转前比较)

public String longestPalindrome(String s) {
    if (s.equals(""))
        return "";
    String origin = s;
    String reverse = new StringBuffer(s).reverse().toString();
    int length = s.length();
    int[][] arr = new int[length][length];
    int maxLen = 0;
    int maxEnd = 0;
    for (int i = 0; i < length; i++)
        for (int j = 0; j < length; j++) {
            if (origin.charAt(i) == reverse.charAt(j)) {
                if (i == 0 || j == 0) {
                    arr[i][j] = 1;
                } else {
                    arr[i][j] = arr[i - 1][j - 1] + 1;
                }
            }
            /**********修改的地方*******************/
            if (arr[i][j] > maxLen) {
                int beforeRev = length - 1 - j;
                if (beforeRev + arr[i][j] - 1 == i) { //判断下标是否对应
                    maxLen = arr[i][j];
                    maxEnd = i;
                }
                /*************************************/
            }
        }
    return s.substring(maxEnd - maxLen + 1, maxEnd + 1);
}