leetcode5[Longest Palindromic Substring]

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

所谓回文串,就是指一个字符串正序和倒序完全一致,必须"aba","baab"等,本题求的是一个字符串最长的回文子串,比如"aabbaccddcc"的最长回文子串就是"ccddcc"。

首先想到的是暴力解法,遍历每一个字符作为子串的开端,字符串从后往前的每一个字符作为子串的结尾,然后再进行回文串的判断,因为要进行三次循环,所以总的时间复杂度为O(n^{3}),结果超时,但扔然通过93个测试样例。

暴力法的思路是从两端向中间找出所有的回文子串,这样必然存在大量的重复对比,比如"abdcfdba",a对比了一次,b对比了两次,d对比了三次,明显不合理。

优化暴力方法的思路就是动态规划,动态规划的核心思想就是大问题化为小问题来解决 ,假如已知某子串s1为回文串,比如"abba",那么s加上前一位和向后一位的新子串s2为回文串的条件就是加的这两个字符相同,比如"cabbac",描述如下(截图)。

因此需要一个二维数组来存储p(i,j)的值 ,依次求出长度为1到N(字符串长度)的子串是否为回文串,其中1和2需要单独判断,3到N利用动态方程求得,时间复杂度为O(n^{2}),缺点是需要额外的空间存储二维数组,长字符串会有较大开销,实现代码如下。

class Solution {
    public String longestPalindrome(String s) {
        int length = s.length();
        Boolean p[][] = new Boolean[length][length];
        int maxlen = 0;
        int start=0,end=0;
        for(int len = 1 ; len <= length ; ++len)
            for(int i = 0;  i< length ; ++i)
            { 
                int j = i+len-1;
                if(j>=length)
                    break;
                p[i][j] = (len==1||len==2||p[i+1][j-1])&&s.charAt(i)==s.charAt(j);
                if(p[i][j]&&len>maxlen)
                {
                    start = i;
                    end = j;
                    maxlen = len;
                }

            }
        return length>1?s.substring(start,end+1):s;

             
    }
}

另一种思路就是从中间向两端查找,也就是遍历每一个字符作为回文子串的中间点,然后向两边对比,这样的时间复杂度为O(n^{2})。由于回文子串的中心可以是一个字符,也可以是两个字符,所以要分别处理。这种方法也叫做中心扩展法,实现代码如下。 

class Solution {
    public String longestPalindrome(String s) {
        int length = s.length();
        if(length<2)
            return s;
        int start = 0, end = 0, maxlen = 0;
        for(int i = 0;i < length;++i)
        {
            int lenOdd = expandCenter(s,i, i);
            int lenEven = expandCenter(s,i, i+1);
            int len = Math.max(lenOdd,lenEven);
            if(len>maxlen)
            {
                maxlen = len;
                start = i-(len-1)/2;
                end  = i+len/2;
            }
        }
        return s.substring(start,end+1);
        
             
    }
    public int expandCenter(String s,int L,int R)
    {
        int len = (L==R?-1:0);
        while(L>=0&&R<s.length())
        {
            if(s.charAt(L)!=s.charAt(R))
                break;
            len+=2;
            L--;
            R++;
        }
        return len;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章