leetcode 5. Longest Palindromic Substring

题目
求最长的回文子串。这道题的最优解法当然是马拉车算法。
首先要说一下最基本的方法。最暴力的就不说了,太费时间。稍微暴力一点的就是:以每个位置为中心向两侧扩展,看看能够扩出多长的子串。但是这里就面临一个问题。就是回文串分为奇回文和偶回文。这样在代码上倒是可以实现,需要分为两种情况来扩展。1.把当前点作为奇回文的中心,2.把当前点和前面一个点作为偶回文的第一对回文字符。这样子再去暴力扩展。
而manacher算法的优化其实就是优化了暴力扩展中的一些重复的工作。
首先,在字符串的首尾和每个字符之间都加上一个特定的字符‘#’。这样操作之后,所有的回文串都会变为奇回文,省去了分情况的麻烦。
然后是,用c来记录当前回文中心的位置,r记录当之前所有回文半径扩到的位置,p[]来记录每个位置的回文半径。
当前到达的位置i,如果i并没有处于r所扩到的位置,则记录i位置的回文半径为1,当前位置需要继续向两边扩充比较。
如果i处于r所扩充的位置内,需要看i点关于r的回文中心的对称点j,来看一下j点的回文半径大小如何?如果没有超出r扩出的范围,那么i的回文半径等于j的回文半径。如果超出了,i的回文半径就等于i到r的长度。如果正好压线,那么i的回文半径暂时等于i到r的长度,需要继续向外扩充比较。

class Solution {
    public String longestPalindrome(String s) {
        if(s==null || s.length()==0) return s;
        char[] charArr = manacherString(s);
        int[] p = new int[charArr.length];
        int c = -1;
        int r = -1;
        int max = Integer.MIN_VALUE;
        int result = 0;
        for(int i=0;i!=charArr.length;i++){
            p[i] = r>i?Math.min(p[2*c-i],r-i):1;
            while(i+p[i]<p.length && i-p[i]>-1){
                if(charArr[i-p[i]]==charArr[i+p[i]]){
                p[i]++;
                }else{
                    break;
                }
            }
            if(i+p[i]>r){
                r = i+p[i];
                c = i;
            }
            if(p[i]>max){
                result = i;
                max = p[i];
            }
        }
        String s1 = "";
        for(int i=result+1-max;i<result+max;i++){
            if(charArr[i]!='#') s1+=charArr[i];
        }
        return s1;
    }
    public static char[] manacherString(String s){
        char[] chr = s.toCharArray();
        char[] res = new char[chr.length*2+1];
        int index = 0;
        for(int i=0;i<res.length;i++){
            res[i] = (i&1)==0?'#':chr[index++];
        }
        return res;
    }
}

爷要哭了,总是记不住这个算法的细节。。。
发现个特牛逼的动态规划,说白了动态规划就是申请开辟一块空间,然后把过程中的一些量值记录下来,这样再查找使用的时候就会比较快速和方便。
dp[i][j]=1代表i到j位置的字符串为回文字串,因此就可以通过判断s[i+1]和s[j-1]是否相同,以及dp[i+1][j-1]是否为1.

class Solution {
    public String longestPalindrome(String s) {
        if(s.isEmpty()) return "";
        int len = s.length();
        if(len==1) return s;
        char[] num = s.toCharArray();
        int[][] dp = new int[len][len];
        int start = 0;
        int longest = 1;
        for(int i=0;i<len;i++){
            dp[i][i] = 1;
            if(i<len-1){
                if(num[i]==num[i+1]){
                    dp[i][i+1] = 1;
                    start = i;
                    longest = 2;
                }
            }
        }
        for(int l = 3;l<=len;l++){
            for(int i = 0;i<len-l+1;i++){
                int j = i+l-1;
                if(num[i]==num[j] && dp[i+1][j-1]==1){
                    dp[i][j] = 1;
                    start = i;
                    longest = l;
                }
            }
        }
        return s.substring(start,start+longest);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值