[LeetCode] 4. Longest Palindrome Substring 分析+代码

来源:互联网 发布:sql 多个case when 编辑:程序博客网 时间:2024/05/17 23:08

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Input: "babad"


Output: "bab"


Note: "aba" is also a valid answer.

Input: "cbbd"


Output: "bb"

native的方法 2层循环 验证每一个可能的子字符串是否是回文,再加一层验证回文的函数要一层循环,总的是 O(n3)复杂度

public String longestPalindrome(String s) {          if(s==null) return null;          // String[][] dp= new String[1000][1000];          // Arrays.fill(dp,1);          int max=1;          String result=s.substring(0,1);          for(int i=0;i<s.length()-1;i++){              for(int j=i+1;j<s.length();j++){                  String temp=s.substring(i,j+1);                  if(ifPalin(temp)){                      if(max<temp.length()){                          max=temp.length();                          result=temp;                      }                      if(max==s.length())                        return result;                  }              }          }                    return result;                }            public boolean ifPalin(String s){          if(s==null) return true;          int start=0;          int end=s.length()-1;                    while(start<end){              if(s.charAt(start++)!=s.charAt(end--)){                  return false;              }          }                    return true;      }  

brutal force的算法把所有的可能的substring 都去做了验证是否事palindrome. 为了优化,我们首先分析如何能避免不必要的重复计算。 

通过对回文性质的分析,我们可以看出来: 如果中间的某一段子串sub是回文,如果sub两侧的字符是一样的,那么作为一个整体也是回文。例如:


abcdcba      : d是回文,cdc那么就是回文。 如果你再想一下,cdc是回文,两侧b是一样的,bcdcb也是回文。咦,那么abcdcba就是回文了呗。


通过上个例子我们直接知道了答案。这是特例,那么对于一般情况如何是好呢?所以第一个思路就是根据顺向的思维推导出来的:


我们申明一个dp[][]来储存状态。 对于dp[i][j]来说, 其意义就是 s.substring(i,j+1)是不是回文。


(1)既然我们不知道哪里为中心,向外拓展就能得到答案。那么就以每个字符为中心,向外拓展,保存一个最大的量,问题就解决了!


我们得初始化下dp, 单个字符是,所以dp[i][i]=true.


可是还有种情况, abcddcba,中间是两个,不是一个,这也能构成回文,这怎么办!


其实也好办,我们就看看s.charAt(i)==s.charAt(i+1),如果是,就是回文,我们就set  dp[i][i+1]=true


有了基础的case,我们1层for循环移动中心点,用两个指针start,end,分别拓展这两种情况,来分析回文,即可找出最大值。

第一种,用dp的方法,dp的思路是用以前做出来的结果作为基础,然后推导出新的结果,首先要分析特例: 

如果P[i,j]为真,当且仅当si-1,si-2...sj-1,sj这一个子串都为palindrome。例如:s[] = skrdjdre那么P[2][6] = true,因为s[2]=r=s[6],且djd为回文。

代码如下:

public String longestPalindrome(String s) {           if(s==null) return null;          boolean[][] dp= new boolean[s.length()][s.length()];          //define dp[i][j] is if s.substring(i,j+1) is palindrome:          int max=1;          String result=s.substring(0,1);          for(int i=0;i<s.length();i++){              dp[i][i]=true;          }          for(int i=0;i<s.length()-1;i++){              if(s.charAt(i)==s.charAt(i+1)){                  dp[i][i+1]=true;                  result=s.substring(i,i+2);                  max=2;              }          }          for(int i=1;i<s.length()-1;i++){               int start=i-1,end=i+1;  //aba的情况               while(start>=0 && end<=s.length()-1){                  if(dp[i][i] && s.charAt(start)==s.charAt(end)){                      dp[start][end]=true;                      if(max<end-start+1){                          max=end-start+1;                          result=s.substring(start,end+1);                      }                  } else {                      break;                  }                  start--;end++;               }               start=i-1;end=i+2;  //abba的情况               while(start>=0 && end<=s.length()-1){                  if(dp[i][i+1] && s.charAt(start)==s.charAt(end)){                      dp[start][end]=true;                      if(max<end-start+1){                          max=end-start+1;                          result=s.substring(start,end+1);                      }                  } else{                      break;                  }                  start--;end++;               }          }                    return result;              }