最长回文子序列(不连续)以及最长回文子串(连续)
整理了一下关于回文子序列和回文子串的程序。
其中(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 }