最长回文子序列(不连续)以及最长回文子串(连续)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长回文子序列(不连续)以及最长回文子串(连续)相关的知识,希望对你有一定的参考价值。

整理了一下关于回文子序列和回文子串的程序。

其中(1)和(2)是采用动态规划的思想写出的回文子序列的程序,这种子序列就是在原始的串中可以不连续,比如对于那种要求删除几个字符来得到最长的回文字符串的题就是这种情况。

比如caberbaf.  最长的子序列是5 abeba 或者abrba。而子串最长只有1

(3)(4)(5)都是最长子串的求法。(3)是暴力求解,(4)是改进的暴力求解。(5)采用的是动态规划的方法。

  1 #include <iostream>
  2 #include <string>
  3 #include <vector>
  4 #define MAX 1000
  5 using namespace std;
  6 
  7 /***************************************************************************************/
  8 /***************************************************************************************/
  9 
 10 /*(1)采用循环
 11 最长回文子序列 (不连续地---序列,子串是连续地)
 12 动态规划
 13 **/
 14 int maxPalindromeLen(string s){
 15     int len = s.length();
 16     if (len == 0)
 17     {
 18         return 0;
 19     }
 20     else if (len == 1)
 21     {
 22         return 1;
 23     }
 24     vector<int> max_Palind(len);
 25     //init
 26     for (size_t i = 0; i < len; i++)
 27     {
 28         max_Palind[i] = 0;
 29     }        
 30     max_Palind[0] = 1;
 31 
 32     for (int j = 0; j < len; j++)
 33     {
 34         for (int i = 0; i <j; ++i)
 35         {
 36             if (max_Palind[i]<max_Palind[i + 1] + (s[i] == s[j]) * 2){
 37                 max_Palind[i] = max_Palind[i + 1] + (s[i] == s[j]) * 2;
 38             }
 39         }
 40         max_Palind[j] = 1;
 41     }
 42     return max_Palind[0];
 43 }
 44 
 45 /***************************************************************************************/
 46 /***************************************************************************************/
 47 int max(int a, int b)
 48 {
 49     if (a > b)
 50     {
 51         return a;
 52     }
 53     else
 54     {
 55         return b;
 56     }
 57 
 58 }
 59 /*(2) 采用递归
 60 最长回文子序列 (不连续地---序列,子串是连续地)
 61 最优子结构
 62 假设 X[0 ... n-1]  是给定的序列,长度为n.  让 L(0,n-1) 表示 序列 X[0 ... n-1] 的最长回文子序列的长度。
 63 
 64 1. 如果X的最后一个元素和第一个元素是相同的,这时:L(0, n-1) = L(1, n-2) + 2 , 
 65 还以 “BBABCBCAB” 为例,第一个和最后一个相同,因此 L(1,n-2) 就表示蓝色的部分。
 66 
 67 2. 如果不相同:L(0, n-1) = MAX ( L(1, n-1) ,  L(0, n-2) )。 
 68 以”BABCBCA” 为例,L(1,n-1)即为去掉第一个元素的子序列,L(0, n-2)为去掉最后一个元素。
 69 */
 70 int lps(string &s, int i, int j)
 71 {
 72     if (i == j)
 73     {
 74         return 1;
 75     }
 76     if (i > j)
 77     {
 78         return 0;
 79     }
 80     //如果首尾相同
 81     if (s[i] == s[j])
 82     {
 83         return lps(s, i + 1, j - 1) + 2;
 84     }
 85     //首尾不同,两种情况
 86     return max(lps(s, i + 1, j), lps(s, i, j - 1));
 87 }
 88 
 89 /***************************************************************************************/
 90 /***************************************************************************************/
 91 
 92 /*(3)最长回文子串(就是连续地)
 93 暴力循环
 94 */
 95 bool isPalindrome(string s)
 96 {
 97     int len = s.size();
 98     for (int i = 0; i < len / 2; i++)
 99     {
100         if (s[i] != s[len - i - 1])
101         {
102             return false;
103         }
104     }
105     return true;
106 }
107 int maxPalindromeLength(string s)
108 {
109     int len = s.size();
110     int maxLength = 0;
111     for (int i = 0; i < len - 1; i++)
112     {
113         for (int j = 1; j <= len - i; j++)
114         {
115             //构造一个子串,从i开始的j个字符
116             string substr = s.substr(i, j);
117             if (isPalindrome(substr))
118             {
119                 int len = substr.size();
120                 if (len > maxLength)
121                 {
122                     maxLength = len;
123                 }
124             }
125         }
126     }
127     return maxLength;
128 }
129 
130 /***************************************************************************************/
131 /***************************************************************************************/
132 
133 /*(4)改进的最长回文子串(o(n的平方))
134 以中心轴进行判断
135 */
136 int l2r(string s,int mid)
137 {
138     int l = mid - 1, r = mid + 1;
139     int len = s.size();
140     while (s[mid] == s[r])//考虑那种中间相同的情况 比如abbc 相当于bb为中心
141     {
142         r++;
143     }
144     while (l >= 0 && r < len && s[l] == s[r])
145     {
146         l--;
147         r++;
148     }
149     return r - l - 1;
150 }
151 int maxl2r(string s)
152 {
153     int len = s.size();
154     if (len == 0)
155     {
156         return 0;
157     }
158     else if (len == 1)
159     {
160         return 1;
161     }
162     int maxlength = 0;
163     for (int i = 0; i < len; i++)
164     {
165         int len = l2r(s, i);
166         if (maxlength < len)
167         {
168             maxlength = len;
169         }
170     }
171     return maxlength;
172 }
173 
174 /***************************************************************************************/
175 /***************************************************************************************/
176 
177 /*(5)以动态规划的方法解决最长回文子串(连续地)
178 递推式表示在s[i] = s[j]情况下,如果s[i+1..j-1]是回文子串,则s[i..j]也是回文子串;
179 如果s[i+1..j-1]不是回文子串,则s[i..j]也不是回文子串。
180 
181 初始状态:
182 
183 c[i][i] = 1
184 c[i][i+1] = 1 if s[i] == s[i+1]
185 */
186 int maxDynamicLength(string s)
187 {
188     int len = s.size();
189     if (len == 0)
190     {
191         return 0;
192     }
193     else if (len == 1)
194     {
195         return 1;
196     }
197 
198     int i, length;
199     int longest = 1;
200     bool c[MAX][MAX] = {false};
201     //init
202     for (i = 0; i < len; i++)
203     {
204         c[i][i] = true;
205     }
206     for (int i = 0; i < len - 1; i++)
207     {
208         if (s[i] == s[i + 1])
209         {
210             c[i][i + 1] = true;
211             longest = 2;
212         }
213     }
214 
215     //上面已经解决了2个字符的情况;下面从字符长度为3开始
216     for (length = 3; length <= len; length++)
217     {
218         for (i = 0; i < len - length + 1; i++)
219         {
220             int j = i + length - 1;//i是字符起点索引 j是终止索引
221             if (s[i] == s[j] && c[i+1][j-1])
222             {
223                 c[i][j] = true;
224                 longest = length;
225             }
226         }
227     }
228     return longest;
229 }
230 string longestPalindromeDP(string s) {
231     int n = s.length();
232 
233     int longestBegin = 0;
234 
235     int maxLen = 1;
236 
237     bool table[1000][1000] = { false };
238 
239     for (int i = 0; i < n; i++) {
240 
241         table[i][i] = true;   //前期的初始化
242 
243     }
244 
245     for (int i = 0; i < n - 1; i++) {
246 
247         if (s[i] == s[i + 1]) {
248 
249             table[i][i + 1] = true; //前期的初始化
250 
251             longestBegin = i;
252 
253             maxLen = 2;
254 
255         }
256 
257     }
258 
259     for (int len = 3; len <= n; len++) {
260 
261         for (int i = 0; i < n - len + 1; i++) {
262 
263             int j = i + len - 1;
264 
265             if (s[i] == s[j] && table[i + 1][j - 1]) {
266 
267                 table[i][j] = true;
268 
269                 longestBegin = i;
270 
271                 maxLen = len;
272 
273             }
274 
275         }
276 
277     }
278 
279     return s.substr(longestBegin, maxLen);
280 
281 }
282 
283 /***************************************************************************************/
284 /***************************************************************************************/
285 
286 int main(int args, char* argv[])
287 {
288     string s;
289     while (cin >> s)
290     {
291         int len = s.size() - 1;
292         cout << maxPalindromeLength(s) << endl;
293         //cout << lps(s, 0, len) << endl;
294         //cout << maxl2r(s) << endl;
295         //cout << maxDynamicLength(s) << endl;
296         //string substr = longestPalindromeDP(s);
297         //cout << substr << ":" << substr.size() << endl;
298     }
299     return 0;
300 }

 

以上是关于最长回文子序列(不连续)以及最长回文子串(连续)的主要内容,如果未能解决你的问题,请参考以下文章

算法 ---- 子序列系列问题题解(子序列编辑距离回文系列问题)

算法 ---- 子序列系列问题题解(子序列编辑距离回文系列问题)

算法 ---- 子序列系列问题题解(子序列编辑距离回文系列问题)

Java 求解最长回文子序列

子序列与子串问题

子序列与子串问题