最长回文子串

最长回文子串一般有以下两种情况:

问题描述1:给定一个字符串,求它的最长回文子串的长度,并且回文子串的字符在原字符串中必须连续。

分析:很明显可以使用暴力法求解,枚举出所有的子串,分别判断其是否为回文。但是这种方法效率比较低,而且时间复杂度太高,并且如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的,等等。

        我们可以对其进行优化,因为回文串是以中间的字符为中心左右对称的,例如回文串“aba”,以b为中心,它的左端和右端对称,都是a。

        所以我们可以枚举中心位置,从中心位置向两边扩展,记录并更新得到的最长的回文长度。这里要注意回文串的长度是计数还是偶数,因此需要分别进行讨论。

        具体的Java代码如下,语句都很通用,读者可以很容易的转换为其他语言:

        

 1 import java.util.*;
 2  class Test {
 3       public static int maxhuiwenlength(StringBuilder str){
 4           if(str.length()==0)return 0;                   //如果长度为空字符串,直接返回0
 5           int i,j,max=0,p;                               //max记录最长的长度
 6           int n=str.length();                            //求字符串长度
 7           for(i=0;i<n;i++)
 8           {
 9               for(j=0;(i-j)>=0 && (i+j)<n;j++)           //假设长度为奇数的回文串
10                   if(str.charAt(i-j)!=str.charAt(i+j))break;
11               p=(j-1)*2+1;
12               if(p>max)max=p;
13               for(j=0;(i-j)>=0 && (i+j+1)<n;j++)         //假设长度为偶数的回文串
14                   if(str.charAt(i-j)!=str.charAt(i+j+1))break;
15               p=(j-1)*2+2;
16               if(p>max)max=p;
17           }  
18           return max;                                   //返回回文串长度
19       }        
20     }
21  
22 public class Main {
23     public static void main(String[] args) {
24       StringBuilder str=new StringBuilder("123458"); 
25      System.out.print("字符串:"+str+"的最大回文子串长度为:"+Test.maxhuiwenlength(str));
26     }
27 
28 }
View Code

问题描述2:给定一个字符串,求它的最长回文子串的长度,并且回文子串的字符在原字符串中可以不连续。也就是说可以删除原字符串中的一个或多个字符。

分析:该问题与问题1相比,有了一定的难度,难度在于可以删除原字符串中的字符,但是基本思想还是和问题1一样,需要在问题1上做一些改进。

        同样需要分别考虑回文串是奇数还是偶数,无论哪种情况,都遵循这个过程。

                  当扫描到两端字符相等时,两端都要扩展,如果不相等,则要分两步进行:

                                                                                                            第一步,固定右端,向左扫描一遍,如果发现相等,则两端同时扩展,长度加2.否则左指针-1

                                                                                                            第二步,固定左端,向右扫描一遍,如果发现相等,则两端同时扩展,长度加2.否则右指针+1

         具体的Java代码如下,代码写法比较通用,读者可以很容易转换为其他语言。

 1 import java.util.*;
 2  class Test {
 3       public static int maxhuiwenlength(StringBuilder str){
 4           if(str.length()==0)return 0;                   //如果长度为空字符串,直接返回0
 5           int i,j,max=0,p;                               //max记录最长的长度,p记录临时最长长度
 6           int n=str.length();                            //求字符串长度
 7           int low,high;                                  //两个指针分别指向两端
 8           for(i=1;i<n;i++)
 9           {   
10               p=1;                                      //寻找以i为中心的奇数长度的回文,最少长度也为1
11               low=i-1;high=i+1;
12               while(low>=0 && high<n)
13               {
14                   if(str.charAt(low)==str.charAt(high))   //如果两端相等,两端同时扩展,长度加2
15                       {
16                         low--;
17                         high++;
18                         p=p+2;                            
19                       }
20                   else{                                  //如果两端不相等
21                       int t=low;
22                       while(--low>=0 && high<n)          //右端固定不变,向左扫描一遍
23                           if(str.charAt(low)==str.charAt(high))  //扫描到相等时,两边同时扩展,长度加2
24                           {
25                               high++;
26                               p=p+2;
27                           }
28                       low=t;
29                       while(low>=0 && ++high<n)          //左端固定不变,向右扫描一遍
30                           if(str.charAt(low)==str.charAt(high))     //扫描到相等时,两边同时扩展,长度加2
31                           {
32                               low--;
33                               p=p+2;
34                           }
35                   }
36               }
37               if(p>max)max=p;                          //更新最长长度
38               
39               p=0;                                     //寻找以i-1,i为中心的偶数长度的回文
40               low=i-1;high=i;
41               while(low>=0 && high<n)
42               {
43                   if(str.charAt(low)==str.charAt(high))       //如果两端相等,两端同时扩展,长度加2
44                       {
45                         low--;
46                         high++;
47                         p=p+2;
48                       }
49                   else{
50                       int t=low;
51                       while(--low>=0 && high<n)                     //右端固定不变,向左扫描一遍
52                           if(str.charAt(low)==str.charAt(high))     //扫描到相等时,两边同时扩展,长度加2
53                           {
54                               high++;
55                               p=p+2;
56                           }
57                       low=t;
58                       while(low>=0 && ++high<n)                     //左端固定不变,向右扫描一遍
59                           if(str.charAt(low)==str.charAt(high))     //扫描到相等时,两边同时扩展,长度加2
60                           {
61                               low--;
62                               p=p+2;
63                           }
64                   }
65               }
66               if(p>max)max=p;                           //更新最长长度
67           }  
68           if(max==0)max=1;                              //因为只要字符串不为空,回文串最少也为1
69           return max;                                   //返回回文串长度
70       }        
71     }
72  
73 public class Main {
74     public static void main(String[] args) {
75       StringBuilder str=new StringBuilder("123251"); 
76      System.out.print("字符串:"+str+"的最大回文子串长度为:"+Test.maxhuiwenlength(str));
77     }
78 
79 }
View Code

 

posted @ 2016-04-25 13:09  成功=坚持+努力+目标  阅读(218)  评论(0编辑  收藏  举报