LeetCode 5.最長迴文子串的三種解法

LeetCode 5.最長迴文子串

解法一:
直接使用中心擴展判斷迴文串,具體方法在:LeetCode 132.分割回文串II
再從大到小枚舉長度,若區間[i,j+1)爲迴文串,輸出。

class Solution {
    private boolean[][] judge(char []ch)
    {
        int m=ch.length;
        boolean [][]f=new boolean[m][m];
        for(int i=0;i<m;i++)
            Arrays.fill(f[i],false);
        for(int c=0;c<m;c++)
        {
            for(int j=c,i=c;i>=0&&j<m&&ch[i]==ch[j];)
            {
                f[i][j]=true;
                i--;j++;
            }
        }
         for(int c=0;c<m;c++)
        {
            for(int j=c+1,i=c;i>=0&&j<m&&ch[i]==ch[j];)
            {
                f[i][j]=true;
                i--;j++;
            }
        }
        return f;
    }
    public String longestPalindrome(String s) {
        int n=s.length();
        char []ch=s.toCharArray();
        if(n==0)
            return "";
        boolean [][]sign=judge(ch);
        for(int len=n;len>0;len--)
        {
            for(int i=0,j;i<=n-len;i++)
            {
                j=i+len-1;
                if(sign[i][j])
                    return s.substring(i,j+1);
            }
        }
        return "";
    }
}

解法二:動態規劃
確定狀態:
如果子區間[i+1..j-1]是迴文串,且s[i]==s[j],那麼子區間[i....j]就是迴文串。
找到區間長度最大的迴文串即所求。
狀態:設f[i][j]爲區間[i.....j]是否爲迴文串。
轉移方程: f[i][j]=f[i+1][j-1]&&ch[i]==ch[j]
初始狀態:
區間長度爲1,即一個字母爲迴文串:f[i][i]=true
區間長度爲2,兩個字母相等的爲迴文串: f[i][i+1]=true (ch[i]==ch[i+1])
計算順序: 按照區間從小到大計算。

class Solution {
    public String longestPalindrome(String s) {
        char []ch=s.toCharArray();
        int n=ch.length;
        if(n==0)
            return "";
        boolean [][]f=new boolean[n][n];
        for(int i=0;i<n;i++)
        {
            f[i][i]=true;
        }
        for(int i=0;i<n-1;i++)
        {
            if(ch[i]==ch[i+1])
                f[i][i+1]=true;
        }
        for(int len=3;len<=n;len++)
        {
            for(int i=0,j;i<=n-len;i++)
            {
                j=i+len-1;
                f[i][j]=f[i+1][j-1]&&ch[i]==ch[j];
            }
        }
        for(int len=n;len>0;len--)
        {
            for(int i=0,j;i<=n-len;i++)
            {
                j=i+len-1;
                if(f[i][j])
                    return s.substring(i,j+1);
            }
        }
        return "";
    }
}

解法三:評論大神解法

效率很高,時間大約2ms,將回文串中間部分看作一個字符,甚至比馬拉車算法還快(23ms)

class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
//         保存起始位置,測試了用數組似乎能比全局變量稍快一點
        int[] range = new int[2];
        char[] str = s.toCharArray();
        for (int i = 0; i < s.length(); i++) {
//             把迴文看成中間的部分全是同一字符,左右部分相對稱
//             找到下一個與當前字符不同的字符
            i = findLongest(str, i, range);
        }
        return s.substring(range[0], range[1] + 1);
    }
    
    public static int findLongest(char[] str, int low, int[] range) {
//         查找中間部分
        int high = low;
        while (high < str.length - 1 && str[high + 1] == str[low]) {
            high++;
        }
//         定位中間部分的最後一個字符
        int ans = high;
//         從中間向左右擴散
        while (low > 0 && high < str.length - 1 && str[low - 1] == str[high + 1]) {
            low--;
            high++;
        }
//         記錄最大長度
        if (high - low > range[1] - range[0]) {
            range[0] = low;
            range[1] = high;
        }
        return ans;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章