求一个字符串中的最长回文字符串

1. 参考文章http://www.leetcode.com/2011/11/longest-palindromic-substring-part-i.html

2. 文章中阐述了五种方法

  (1)将str反转然后得到rstr,然后求str和rstr的最长公共子串。每次得到一个最长公共子串候选,还需要对子串下标和反转子串的原始下标进行判断,看是否相等:相等则得到的是合理的回文串;否则不合理。如果求最长公共子串使用DP算法,则时间复杂度为O(N2),空间复杂度为O(N2);如果采用广义后缀树(GST),则时间复杂度为O(2N)(具体算法还没细看)。

  (2)暴力搜索,时间复杂度为O(N3)(代码中的方法1)

  (3)动态规划时间复杂度为O(N2),空间复杂度为O(N2)(代码中的方法2)

  (4)从中间到两边扩展判断,时间复杂度为O(N2),空间复杂度为O(1)(代码中的方法3)

  (5)线性算法,这个算法技巧性非常强,有些地方还不是很清楚。时间复杂度为O(N),空间复杂度为O(N)(代码中的方法5)

3. 重点掌握(2)(3)(4)

4. 感觉直接使用后缀树也可以得到线性时间的算法,具体算法有空实现。

5. 代码如下:

View Code
  1 #include <iostream>
  2 #include <cassert>
  3 #include <string>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 //方法一:暴力搜索
  8 string IsPalindrome1(string str)
  9 {
 10     if (str=="")
 11     {
 12         return "";
 13     }
 14     int n=str.length();
 15     int maxLength=-1;
 16     int maxIndex;
 17     for (int i=0;i<n;i++)
 18     {
 19         for (int j=i;j<n;j++)
 20         {
 21             int start=i;
 22             int end=j;
 23             bool flag=true;
 24             while (start<=end)
 25             {
 26                 if (str[start]!=str[end])
 27                 {
 28                     flag=false;
 29                     break;
 30                 }
 31                 start++;
 32                 end--;
 33             }
 34             int tmpLength=j-i+1;
 35             if (flag && tmpLength>maxLength)
 36             {
 37                 maxLength=tmpLength;
 38                 maxIndex=i;
 39             }
 40         }
 41     }
 42     return str.substr(maxIndex,maxLength);
 43 }
 44 
 45 //方法2:动态规划
 46 string IsPalindrome2(string str)
 47 {
 48     if (str=="")
 49     {
 50         return "";
 51     }
 52     int n=str.length();
 53     int maxIndex=0;
 54     int maxLength=1;
 55     bool IsPal[1000][1000]={false};
 56     //bool **IsPal=new bool*[n];
 57     //for (int i=0;i<n;i++)
 58     //{
 59     //    IsPal[i]=new bool[n];
 60     //}
 61     //for (int i=0;i<n;i++)
 62     //{
 63     //    for (int j=0;j<n;j++)
 64     //    {
 65     //        IsPal[i][j]=false;
 66     //    }
 67     //}
 68     for (int i=0;i<n;i++)
 69     {
 70         IsPal[i][i]=true;
 71     }
 72     for (int i=0;i<n-1;i++)
 73     {
 74         if (str[i]==str[i+1])
 75         {
 76             IsPal[i][i+1]=true;
 77             maxIndex=i;
 78             maxLength=2;
 79         }
 80     }
 81     for (int len=3;len<=n;len++)
 82     {
 83         for (int i=0;i<=n-len;i++)
 84         {
 85             int j=i+len-1;
 86             if (IsPal[i+1][j-1] && str[i]==str[j])
 87             {
 88                 IsPal[i][j]=true;
 89                 maxIndex=i;
 90                 maxLength=len;
 91             }
 92         }
 93     }
 94     //for (int i=0;i<n;i++)
 95     //{
 96     //    delete[] IsPal[i];
 97     //}
 98     //delete[] IsPal;
 99     return str.substr(maxIndex,maxLength);
100 }
101 
102 
103 //从中心向两端扩展
104 string expandAroundCenter(string s,int c1,int c2)
105 {
106     int l=c1;
107     int r=c2;
108     int n=s.length();
109     while (l>=0 && r<=n-1 && s[l]==s[r])
110     {
111         l--;
112         r++;
113     }
114     return s.substr(l+1,r-l-1);
115 }
116 
117 //方法3:从中心向两端扩展
118 string IsPalindrome3(string str)
119 {
120     int n=str.length();
121     if (n==0)
122     {
123         return "";
124     }
125     string longest=str.substr(0,1);
126     for (int i=0;i<n-1;i++)
127     {
128         string p1=expandAroundCenter(str,i,i);
129         if (p1.length()>longest.length())
130         {
131             longest=p1;
132         }
133         string p2=expandAroundCenter(str,i,i+1);
134         if (p2.length()>longest.length())
135         {
136             longest=p2;
137         }
138     }
139     return longest;
140 }
141 
142 //方法5预处理
143 //若输入str="abba"
144 //则输出"^#a#b#b#a#$"
145 string preProcess(string str)
146 {
147     int n=str.length();
148     if (n==0)
149     {
150         return "^$";
151     }
152     string ret="^";
153     for (int i=0;i<n;i++)
154     {
155         ret=ret+"#"+str.substr(i,1);
156     }
157     ret+="#$";
158     return ret;
159 }
160 //方法5:
161 string IsPalindrome5(string str)
162 {
163     string T=preProcess(str);
164     int n=T.length();
165     int *P=new int[n];
166     int C=0;    //对称中心
167     int R=0;    //对此字符串的最右端边界
168     for (int i=1;i<n-1;i++)
169     {
170         int i_mirror=2*C-i;    //
171         P[i]=(R>i)?min(R-i,P[i_mirror]):0;
172         //以i为中心向两端扩充
173         while (T[i+1+P[i]]==T[i-1-P[i]])
174         {
175             P[i]++;
176         }
177         //如果以i为中心扩展的回文字符串右边界
178         //超过R则更新C和R
179         if (i+P[i]>R)
180         {
181             C=i;
182             R=i+P[i];
183         }
184     }
185     int maxLen=0;
186     int currentIndex=0;
187     //搜索最大len和对应下标
188     for (int i=0;i<n-1;i++)
189     {
190         if (P[i]>maxLen)
191         {
192             maxLen=P[i];
193             currentIndex=i;
194         }
195     }
196     delete[] P;
197     return str.substr((currentIndex-1-maxLen)/2,maxLen);
198 }
199 int main()
200 {
201     string str1="aaaaaaaa";
202     string str2="abc";
203     string str3="babcbabcbaccba";
204     cout<<IsPalindrome1(str1)<<endl;
205     cout<<IsPalindrome1(str2)<<endl;
206     cout<<IsPalindrome1(str3)<<endl;
207 
208     cout<<IsPalindrome2(str1)<<endl;
209     cout<<IsPalindrome2(str2)<<endl;
210     cout<<IsPalindrome2(str3)<<endl;
211 
212     cout<<IsPalindrome3(str1)<<endl;
213     cout<<IsPalindrome3(str2)<<endl;
214     cout<<IsPalindrome3(str3)<<endl;
215 
216     cout<<IsPalindrome5(str1)<<endl;
217     cout<<IsPalindrome5(str2)<<endl;
218     cout<<IsPalindrome5(str3)<<endl;
219 
220 }

 

 

posted @ 2012-07-19 16:59  kasuosuo  阅读(1735)  评论(0编辑  收藏  举报