1. 程式人生 > >[leetcode]5.Longest Palindromic Substring

[leetcode]5.Longest Palindromic Substring

自己的暴力解法果真超時了,但是很開心有進步,能把自己腦子裡的演算法給順利翻譯出來了,比剛開始做第一題的感覺好多了,開心。

暴力解法:遍歷

class Solution {
    public String longestPalindrome(String s) {
        char []a=s.toCharArray();
        int maxCount=0;
        String sub="";
        int j=0;
        
        for(int k=0;k<a.length;k++){
            for(int i=k;i<a.length;i++){
                for( j=i;j<a.length;j++){
                    int p=i;int q=j;
                    int flag=0;
                    while(p<=q){
                        if(a[p]!=a[q]){
                            flag=1;
                            break;
                        }
                         p++;
                         q--;
                    }

                    if(flag==0){
                    if((j-i+1)>=maxCount){
                        maxCount=j-i+1;
                        sub=s.substring(i,j+1);
                    }

                }
                
            }
        }
    }
        return sub;
        
    }
}


solution1

看了一眼solution1的大概,想出了一個動態規劃解法,複雜度為o(n2) 在這裡插入圖片描述

For example, S = “caba”, S’= “abac”. The longest common substring between S and S’ is “aba”, which is the answer.

//運用動態規劃,將s和s'的遍歷結果存為矩陣。
c[i][j]表示原字串s,從s[i]起,向前長度為c[i][j]的substring是迴文數 .
這裡a是原字串,k是翻轉的。

    public int [][] matrix(char []a,char[]k){
        int m=a.length;
        int n=k.length;
        int[][]c=new int[m+1][n+1];
        int i=0,j=0;
        
        for(i=0;i<=m;i++) c[i][0]=0;
        for(i=0;i<=n;i++)c[0][i]=0;
        
        for(i=1;i<=m;i++)
            for(j=1;j<=n;j++){
                if(a[i-1]==k[j-1]){
                    c[i][j]=c[i-1][j-1]+1;
                }
                else{
                    c[i][j]=0;
                }
            }
       return c;
    }

比如s="bfaa” s‘=“aafb” 矩陣為: 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 0 0 0 1 2 0 0

為了處理方便, 其中第0列和第0行都預先設為0,c[1…s.length][1…s’.length]才是真正的動態規劃矩陣 相當於c[4][2]中的4對應s[3],2對應s’[1]

如果s[i-1]=s’[j-1],則c[i][j]=c[i-1][j-1]+1;否則,c[i][j]=0 (這個規律畫幾個矩陣試試就明白了)

其中最大數可能為最長的迴文數.即 c[4][2]=2,表示從s的第4個字元(s[3])起,向前滑2個,“aa”(s[2],s[3])為最長迴文數。

特殊情況1:

Let’s try another example: S = “aabfgbaa”, S′ = “aabgfbaa”. The longest common substring between S and S′ is “aab”. Clearly, this is not a valid palindrome. 矩陣為: 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 2 0 0 0 0 1 2 0 0 0 3 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 0 0 0 0 2 1 0 1 2 0 0 0 0 1 3

此時最大的c[i][j]是c【9】【9】=3,表示baa是我們求的是最大回文數,但這恰巧是要討論的特殊情況,baa它不是真的,所以到這裡就要判斷一遍是否是迴文數.

            int p=0;
            int q=sub.length-1;
            int flag=0;
            while(p<=q){
                if(sub[p]!=sub[q]){
                    flag=1;
                    break;
                }
                p++;
                q--;
            }

發現不是。繼續處理。

這種情況下,最長迴文數的範圍就被縮小了,可能在baa中。 如何分析呢? 注意上述矩陣,最大c[i][j]所在的對角線\上的值表示子串baa的可能最大回文數。現在這個問題和原先的問題是一個結構和性質,所以可以採用遞迴的思路

  if(flag==1)
            {
                    return longestPalindrome(String.valueOf(sub));
            }
             
            else
                return String.valueOf(sub);

特殊情況2:

發現又錯了,因為還有"abcdbbfcba"這種情況沒有考慮到。我們上述做法是解決了特殊情況1:真正的結果在子串的子串裡。假如結果在中間那一部分呢?比如這個的“dbbf”中的“bb”才是正確答案。

其實中間這一部分的處理辦法和前面都是一樣的,還是遞迴。 我們主要要判斷中間部分sub2和由上述的sub,哪個的最長迴文數更長?

於是最後一塊的處理變成了,誰長返回誰,注意要保證sub2不為空才能進行處理,所以要判斷 if(s.length()-max-max>0),否則會陣列越界。

 if(flag==1)
            {
                if(s.length()-max-max>0)
                     return longestPalindrome(String.valueOf(sub)).length()>=longestPalindrome(String.valueOf(sub2)).length()?
                longestPalindrome(String.valueOf(sub)):longestPalindrome(String.valueOf(sub2));
                
                else
                    return longestPalindrome(String.valueOf(sub));
            }
             
            else
                return String.valueOf(sub);
        
    }

總結: 特殊情況1,包含了最簡單的情況+“aabfgbaa”(aa藏在假的迴文數baa裡) 特殊情況2,補充了"abcdbbfcba"這種最長迴文數在中間的情況。

class Solution {
   //運用動態規劃,將s和s'的遍歷結果存為矩陣,c[i][j]表示原字串s,從s[i]起,向前長度為c[i][j]的substring是迴文數
    public int [][] matrix(char []a,char[]k){
        int m=a.length;
        int n=k.length;
        int[][]c=new int[m+1][n+1];
        int i=0,j=0;
        
        for(i=0;i<=m;i++) c[i][0]=0;
        for(i=0;i<=n;i++)c[0][i]=0;
        
        for(i=1;i<=m;i++)
            for(j=1;j<=n;j++){
                if(a[i-1]==k[j-1]){
                    c[i][j]=c[i-1][j-1]+1;
                }
                else{
                    c[i][j]=0;
                }
            }
       return c;
    }
    public String longestPalindrome(String s) {
        char []a=s.toCharArray();
        for (int i=0;i<a.length/2;i++){
            char temp=a[i];
            a[i]=a[a.length-1-i];
            a[a.length-1-i]=temp;
        }
       
        
        char []k=s.toCharArray();
                

        int maxCount=0;
        int [][]c=matrix(k,a);
        
        int max=0;
        int maxi=0,maxj=0;
        for(int i=1;i<=k.length;i++){
            for(int j=1;j<=a.length;j++){
                if(c[i][j]>=max){
                    max=c[i][j];
                    maxi=i;
                    maxj=j;
                    
                }
            }
        }
       
        char []sub=s.substring(maxi-max,maxi).toCharArray();
        char [] sub2=new char[s.length()];
        
        if(s.length()-max-max>0)
         sub2=s.substring(max,s.length()-max).toCharArray();
        
            int p=0;
            int q=sub.length-1;
            int flag=0;
            while(p<=q){
                if(sub[p]!=sub[q]){
                    flag=1;
                    break;
                }
                p++;
                q--;
            }
        
        
            

            if(flag==1)
            {
                if(s.length()-max-max>0)
                     return longestPalindrome(String.valueOf(sub)).length()>=longestPalindrome(String.valueOf(sub2)).length()?
                longestPalindrome(String.valueOf(sub)):longestPalindrome(String.valueOf(sub2));
                
                else
                    return longestPalindrome(String.valueOf(sub));
            }
             
            else
                return String.valueOf(sub);
        
    }
   
}