[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);
        
    }
   
}

Solution 2:Dynamic Programming

用一个n2的矩阵
在这里插入图片描述

初始化:整个矩阵初始化为0,表示false。对角线上的元素全为1,表示true(单个字母当然是回文数了)

这个矩阵的下三角对我们来说没有意义,就一直初始化为0


首先是特殊情况

在这里插入图片描述

这个规则对应是j-i==1,就是上三角紧挨着对角线的一条。

 if(j-i==1){
                        if(a[i]==a[j])
                            c[i][j]=1;
                    }

下面是一般情况:
在这里插入图片描述
else if(c[i+1][j-1]==1&&a[i]==a[j]) c[i][j]=1;


整个动态规划的代码如下所示:

class Solution {
   public String longestPalindrome(String s) {
        char []a=s.toCharArray();
        int [][]c=new int[a.length][a.length];
        
        int i=0;
        int j=0;
        
        for(i=0;i<a.length;i++){
            for(j=0;j<a.length;j++){
               if(i==j)c[i][j]=1;
                
                else c[i][j]=0;
            }
        }
        
        for(i=a.length-1;i>=0;i--){
            for(j=a.length-1;j>=0;j--){
                if(i<j){
                    if(j-i==1){
                        if(a[i]==a[j])
                            c[i][j]=1;
                    }
                    
                    else if(c[i+1][j-1]==1&&a[i]==a[j]) c[i][j]=1;
                }
            }
        }
        
          int max=-1;
          int m=-1,n=-1;
          for(i=0;i<a.length;i++){
            for(j=0;j<a.length;j++){
               
                if(c[i][j]==1){
                    if(j-i>max){
                        max=j-i;
                        m=i;
                        n=j;
                    }
                }
                
                
            }
             
             
        }
        
        if(n!=-1&&m!=-1){
             String sub=s.substring(m,n+1);
            return sub;
        }
        else
            return "";
       
    }
    
}

其实还可以优化空间复杂度O(n2)
,因为是这个矩阵真正用到的是上三角,所以可以用有序数对进行顺序存储,这样就只要O(n)的空间复杂度了

Approach 3: Expand Around Center

class Solution {
    public String longestPalindrome(String s) {
        
        if (s == null || s.length() < 1) return "";
        char []a=s.toCharArray();
        
        int i=0;
        int max=0;
        int core=0;
        for(i=0;i<a.length;i++){
            int len1=expandPali(a,i,i);
            int len2=-1;
            if(i+1<a.length)
             len2=expandPali(a,i,i+1);
            
            int maxlen=Math.max(len1,len2);
            
            
            if(maxlen>max){
                max=maxlen;
                core=i;
            }
        }
    
      String sub="";
    
       int start = core - (max - 1) / 2;
       int end = core + max / 2;
      sub=s.substring(start,end+1);
     
      return sub;
       
   }
       
    private int expandPali(char []a,int left, int right){
        while(left>=0&&right<a.length&&a[left]==a[right]){
            left--;
            right++;
        }
        
        return right-left-1;
    }
}

Solution 4

https://www.felix021.com/blog/read.php?2040

猜你喜欢

转载自blog.csdn.net/weixin_36869329/article/details/83928570