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

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

其中(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 }
时间: 2024-10-04 11:05:43

最长回文子序列(不连续)以及最长回文子串(连续)的相关文章

二分求最长单调递增子序列并输出最长的序列(模板)

1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #define N 100005 6 using namespace std; 7 int num[N]; 8 int a[N]; 9 int pre[N]; 10 int pos[N]; 11 12 void print(int x){ 13 if(x==0) return; 14 prin

soj 4421 最长回文子序列

题意: 给你一个字符串,求该字符串的最长回文子序列长度. 解法: 以前做过连续最长回文子串的长度就是通过构造奇数偶数长度的来做,而本题是不连续. 注意到回文字符串的特点是从左边向右边看和从右边向左边看是一样的效果,那么就可以把目标字符串s导致后产生一个t,子串中如果t和s相同那么这个子串就是回文子串,那么就转化为这两个子串求LCS(longest common subsequent)的问题了. 我的代码: #include <set> #include <map> #include

最长不下降子序列nlogn算法详解

今天花了很长时间终于弄懂了这个算法……毕竟找一个好的讲解真的太难了,所以励志我要自己写一个好的讲解QAQ 这篇文章是在懂了这个问题n^2解决方案的基础上学习. 解决的问题:给定一个序列,求最长不下降子序列的长度(nlogn的算法没法求出具体的序列是什么) 定义:a[1..n]为原始序列,d[k]表示长度为k的不下降子序列末尾元素的最小值,len表示当前已知的最长子序列的长度. 初始化:d[1]=a[1]; len=1; (0个元素的时候特判一下) 现在我们已知最长的不下降子序列长度为1,末尾元素

关于最长单调不升子序列和最长单调上升子序列写法

本人巨懒就用了STL lower_bound会找出序列中第一个大于等于x的数 upper_bound会找出序列中第一个大于x的数 对于N个数求最长单调不上升子序列,使用一个数组f[]存下 然后使用一个栈dq,存储不上升序列 把f中的每个元素挨个加到d里面 如果a[i] > d[len],在dq中找到第一个小于f[i]的数w,用f[i]代替 如果w在末尾,由于w < a[i],所以y后面能接的不如a[i]多,w让位给a[i]可以让序列更长 如果w不在末尾,那w本来就是死的,有什么挽救的必要吗(无

Two Rabbits_dp求最长不连续回文子序列

Problem Description Long long ago, there lived two rabbits Tom and Jerry in the forest. On a sunny afternoon, they planned to play a game with some stones. There were n stones on the ground and they were arranged as a clockwise ring. That is to say,

最长回文子序列

题目:给你一个字符串,求它的最长回文子序列,比如"bbbab" 最长回文子序列是"bbbb" 所以返回4,,"abab"最长子序列是"aba"或者"bab" 所以返回3 思路:和之前做的几道dp不同,,,也是我不够变通,,打dp表的时候总习惯左上到右下的顺序,但是这个顺序却固化了我的思维,忽略了对于题解本身含义的理解....... 这个题从下到上开始打表,最重要的是它的含义,,,知道dp[i][j]意味着什

HDU ACM 4745 Two Rabbits 最长非连续回文子序列

分析:两个不同方向开始跳跃,跳过数字相同,就相当于求回文子序列了.用dp求出从一个位置到另一个位置的最长回文子序列,相当于把[1-n]分成区间[1-x]和[x+1,n],结果就是两区间最长回文串子序列之和.枚举中间点i,求出max(dp[1,i]+dp[i+1,n])即得最终结果,回文非连续序列,从前往后,从后往前序列相同,求出区间内最长回文序列,由于是环,分成两部分,1~i,i+1~n,A可从i走到1,然后从n走到i+1,B可从1走到i,从i+1走到n . #include<iostream>

[最长回文子序列Manacher]4.11终于出线了啊!

Manacher用来求最长回文子序列 1.读入字符串,在每个字符前后加一个没有在原字符串中出现的字符,这样不论是奇数或者偶数个都变成了奇数个 例如: M A N A C H E R # M # A # N # A # C # H # E # R # 2.在开头和末尾再添加一个没有在原字符串中出现的字符,这样就不用讨论越界了 例如: # M # A # N # A # C # H # E # R # $# M # A # N # A # C # H # E # R # \0 3.然后从第一位开始计

算法导论_动态规划_最长回文子序列

一.问题的描述 回文序列(Palindromic sequence, Palindrome)是指正向遍历和反向遍历完全相同的序列,例如字符串"AAAAA"显然是一个回文序列,又如字符串"[email protected]"也是一个回文序列.现在,我们要在一个(字符)序列中找出最长回文子序列的长度.例如字符序列"BBABCBCAB",最长回文子序列是"BACBCAB"(可能不唯一),它的长度是7:子序列"BBBBB&q