5. 最长回文子串

 

 

方法一、DP

假设dp[i][j]表示从i到j下标是否是回文串

于是有dp[i][j]=dp[i+1][j-1]^(s[i]==s[j])

时间O(n^2),空间O(n^2)

 1     public String longestPalindrome(String s) {
 2         int len = s.length();
 3         if(len<2){
 4             return s;
 5         }
 6         
 7         boolean dp[][] = new boolean[len][len];
 8         // 每个字符自身都是回文的
 9         for(int i=0;i<len;i++){
10             dp[i][i]=true;
11         }
12         // 由于每个字符自身回文,因此最短也是1
13         int maxLen = 1,begin=0;
14         for(int j=1;j<len;j++){
15             for(int i=0;i<j;i++){
16                 // 首尾不相等,则必然不回文
17                 if(s.charAt(i)!=s.charAt(j)){
18                     dp[i][j]=false;
19                 }else{
20                     // 首尾相同的情况下,前后相差位数不超过2的时候,必然是回文的
21                     if(j-i<3){
22                         dp[i][j]=true;
23                     }else{
24                         // 这里可以由之前的状态获取到当前的状态
25                         dp[i][j]=dp[i+1][j-1];
26                     }
27                 }
28                 // 每次循环后更新最长回文子串的长度与起始位置
29                  if(dp[i][j]==true && (j-i+1)>maxLen){
30                     maxLen = j-i+1;
31                     begin = i;
32                 }              
33             }           
34         }
35         return s.substring(begin,begin+maxLen);
36     }

 

方法二、中心拓展

针对每个元素,我们以此为中心,使用双指针法向两边拓展。

直到不回文为止,每次结束更新最长回文子串的长度与起始位置

时间O(n^2),空间O(1)

 1 class Solution {
 2     public String longestPalindrome(String s) {
 3         int len=s.length();
 4         if(len<2){
 5             return s;
 6         }
 7 
 8         int start=0,end=0;
 9         for(int i=0;i<len;i++){
10             // 需要考虑奇数和偶数2种情况
11             int len_odd = expandCenter(s,i,i);
12             int len_even = expandCenter(s,i,i+1);
13             int maxLen = Math.max(len_odd,len_even);
14             if(maxLen>end-start){
15                 start = i-(maxLen-1)/2;
16                 end = i+maxLen/2;
17             }           
18         }
19         return s.substring(start,end+1);
20     }
21 
22     public int expandCenter(String s,int left,int right){
23         while(left>=0 && right<s.length() && s.charAt(left)==s.charAt(right)){
24             left--;
25             right++;
26         }
27         // 这里由于最后一次循环时start和end分别做了加减,所以是end-start-1+2=start-left-1
28         return right-left-1;
29     }
30 }

 

方法三、马拉车

posted @ 2021-05-24 14:32  jchen104  阅读(44)  评论(0编辑  收藏  举报