您的位置:首页 > 其它

LeetCode题解:Longest Palindromic Substring

2015-08-28 10:50 507 查看
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

题意:给定一个字符串,找出最长的回文子串

解题思路:

Manacher算法

Manacher是求字符串最长回文子串的O(n)时间解决算法,我在这里记录一下我的理解,便于大家理解这个算法,也便于我自己学习。

Manacher算法其实是找出字符串最常回文子串穷举法的优化,所以理解这个算法之前可以先想想穷举法是怎么干的:

对于一个回文字符串,字符串中心向两边延展必然是相同的,所以我们可以从左向右遍历字符串,把每一个位置都看作中心,然后向两边延展,判断是否为回文字符串,记录下最长字符串。无疑,这样的解决办法时间复杂度是O(n^2),而且在查找过程还要区分字符串是奇数还是偶数,以保证选择正确的中心

那么我们能够怎样优化这个算法呢,对于任意一个长度为L的字符串,具有L+1个插入位置。假如这L+1个插入位置都被插入,字符串长度将变成2L+1,也就是说,字符串将始终为奇数,这样判断奇偶的问题就解决了。

所以Manacher算法的第一步,就是向字符串的每一个插入位置插入一个不会出现的字符,一般会选用#。

例如字符串“abba”,处理后变为“#a#b#b#a#”

同样的,我们需要以某个中心点向两边拓展,找回文字符串,所以设置一个数组记录每一个中心点所能得到最长回文字符串的长度,例如:

S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #

P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1

P[i] - 1就是我们要求的最长长度

所以关键就在于,我们要怎么求P[i],而这也是Manacher算法作出优化的地方。

首先,我们用变量id记录中心点的位置。由于回文字符串关于中心对称的特性,那么长度为len的回文字符串关于中心对称的边界为:len/2 + id,我们用mx来表示边界。

所以下面就要求P[i]了,当mx-i大于p[i],意味着对称距离大于回文对称距离,而以id为中心,mx为边界的字符串为回文,所以p[i]=p[j]



当mx-i<=p[i],意味着回文对称距离大于实际对称距离,此时能判断相等的只有图中绿色框内的部分,框外的部分是无法判断的。所以框外的部分仍然需要按照普通方法匹配。最终可以得到代码如下:



代码:

public class Solution {
    public String longestPalindrome(String s) {
        String manacherStr = preProcess(s);

        int center = 0;
        int radius = 0;
        int[] manacherP = new int[manacherStr.length()];
        for(int i = 1; i < manacherStr.length() - 1; i++){
            int iMirror = 2 * center - i;

            if(iMirror >= 0 && iMirror < manacherStr.length()){
                manacherP[i] = radius > i ? Math.min(radius - i, manacherP[iMirror]) : 0;
            }

            int left = i - 1 - manacherP[i];
            int right = i + 1 + manacherP[i];
            while(manacherStr.charAt(left) == manacherStr.charAt(right)){
                left--;
                right++;
                manacherP[i]++;

                if(left < 0 || right >= manacherStr.length()){
                    break;
                }
            }

            if(i + manacherP[i] > radius){
                center = i;
                radius = i + manacherP[i];
            }
        }

        int maxLen = 0;
        int centerIndex = 0;
        for(int i = 1; i < manacherStr.length() - 1; i++){
            if(manacherP[i] > maxLen){
                maxLen = manacherP[i];
                centerIndex = i;
            }
        }

        int start = (centerIndex - maxLen - 1) / 2;
        int end = start + maxLen;
        return s.substring(start, end);
    }

    private String preProcess(String s){
        if(s.length() == 0){
            return "^$";
        }

        StringBuilder sb = new StringBuilder("^");

        for(int i = 0; i < s.length(); i++){
            sb.append("#" + s.charAt(i));
        }

        sb.append("#$");

        return sb.toString();
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: