5. Longest Palindromic Substring

问题描述:寻找字符串的最长回文子序列。

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

Soulution 1 (中心展开):回文序列从中心字符向两边扩展两边元素相同,需要考虑奇数个和偶数个的情况。注意字符串为空的判别: if(s==null || s==""). 注意循环的判断条件不能到length-1为止,这样的话如果字符长度是1 就会返回空字符串。应该在子函数中设置判断。 Time Complexity - O(n2),  Space Complexity - O(1)

class Solution {
    public String longestPalindrome(String s) {
        if(s==null || s=="")
            return "";
        String res = "";
        for(int i=0;i<s.length();i++){
            String temp = findstr(s,i,i); //奇数序列
            if(temp.length()>res.length())
                res = temp;
            temp = findstr(s,i,i+1); //偶数序列
            if(temp.length()>res.length())
                res = temp;
        }
        return res;
    }
    
    String findstr(String s, int i, int j){
        while(i>=0&&j<s.length()&&s.charAt(i)==s.charAt(j)){
            i--;
            j++;
        }
        return s.substring(i+1,j);//注意substring不包含j字符
    }
}

Soulution 2 :Manacher's Algorithm

马拉车算法时间复杂度O(n),这个方法的最大贡献是在于将时间复杂度提升到了线性。

方法重点:(参考Java实现以及讲解讲解的非常形象给出实例,c++实现

1. 为了不用区分奇偶,在字符串每个字符两边加上#,为了防止越界,在字符串头加上$,尾部加上@。(具体解释参考上面的链接)

2. 核心: 之所以时间复杂度低是因为减少了每个字符为中心的判别。需要保存和新的字符串等长的数组,每个元素为对应位置元素为中心的最长回文序列半径(半径包含中心点)。以id为中心最远的回文字符串(不一定是最长的),mx是他的右端点。我们此时的index关于id的对称点为j=2*id-i, 如果i>mx, 那就只能和方法以一样从中心展开找,p[i]=1开始. 如果i<mx,有两种情况:1)2如果i+p[j]>mx, 则至少i到mx是回文序列,p[i]至少是mx-i.

2)如果i+p[j]<mx, p[i]至少是p[j]

得到p[i]最小值之后再向两边寻找直到不满足。

3. 规律:最长子串的长度是半径减1,起始位置是中间位置减去半径再除以2。(参考第二个链接,例子很详细)

注意这里最长字串的半径和中心(reslen,resid)不同于最远字串的半径和中心(id,mx)

4. substring(i,j)不包含j, 长度为a的字符串:substring(i, i+a)

class Solution {
    public String longestPalindrome(String s) {
        if(s==null || s=="")
            return "";
        String t = "$#";
        for(int i=0;i<s.length();i++){
            t = t + s.charAt(i);
            t = t + "#";
        }
        t =t+"@";
        int[] p = new int[t.length()];
        int id=0, j=0,mx=0;
        int reslen = 0, resid =0;
        for(int i=0;i<t.length();i++){
            j = 2*id -i;
            p[i] = i>mx? Math.min(p[j],mx-i):1; //核心部分!!!
            while((i-p[i]>=0)&&(i+p[i]<t.length())&&(t.charAt(i-p[i])==t.charAt(i+p[i])))
                p[i]++;
            if(i+p[i]>mx){
                id=i;
                mx=i+p[i];
            }
            if(p[i]>reslen){
                reslen=p[i];
                resid=i;
            }
        }
        return s.substring((resid-reslen)/2, (resid-reslen)/2+reslen-1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值