LPS(最長回文子序列)
阿新 • • 發佈:2018-02-18
轉化 最長回文 反轉 may substring 子串 def 平均情況 put
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example:
Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Example:
Input: "cbbd" Output: "bb"
這也是《算法導論》中的一個練習題,先給一個自己想的算法(最壞情況的時間復雜度為O(n2)):
class Solution { public: string longestPalindrome(string s) { if (s.size() == 0) return 0; int i = 0, j = s.size() - 1; int flag = 0; int subscript = j; string s1 = ""; while (i < j) { while (i < j) { if (s[i] == s[j]) { s1 += s[j]; subscript = --j; i++; flag = 1; break; } j--; flag = 0; } if (!flag) { j = subscript; i++; } } int k = 0, l = s.size() - 1; flag = 0; subscript = l; string str = s; reverse(str.begin(), str.end()); string s2 = ""; while (k < l) { while (k < l) { if (str[k] == str[l]) { s2 += str[l]; subscript = --l; k++; flag = 1; break; } l--; flag = 0; } if (!flag) { l = subscript; k++; } } int l1 = s1.size(), l2 = s2.size(); s1 = l2 > l1 ? s2 : s1; if (i >= k && i > j) { string str = s1; reverse(str.begin(), str.end()); s1 += str; } else if (k > i && k > l) { string str = s1; reverse(str.begin(), str.end()); s1 += str; } else { string str = s1; reverse(str.begin(), str.end()); s1 += s[l1 >= l2 ? i : k]; s1 += str; } return s1; } };
兩段二重循環的目的是:第一段從右到左縮短str來得到回文子串s1;第二段將原來的字符串反轉,然後同樣的方式得到一個回文子串s2,然後返回最長的。
但結果Leetcode以這種方式拒絕了:
Input: "abcda" Output: "ada" Expected: "a"
但我不覺得我的錯了啊...書上說:character,返回:carac,但在Leetcode竟然錯了。。。看來和書上問題並不太一樣。
完整代碼(可以返回最長回文子串的長度):
#include "stdafx.h" #include <iostream> #include <vector> #include <string> #include <algorithm> class Solution { public: std::string LPS(std::string str) { if (str.size() == 0) return 0; int r1 = 1; int i = 0, j = str.size() - 1; int flag = 0; int subscript = j; std::string s1 = ""; while (i < j) { while (i < j) { if (str[i] == str[j]) { s1 += str[j]; subscript = --j; i++; r1++; flag = 1; break; } j--; flag = 0; } if (!flag) { j = subscript; i++; } } int r2 = 1; int k = 0, l = str.size() - 1; flag = 0; subscript = l; std::string s = str; std::reverse(s.begin(), s.end()); std::string s2 = ""; while (k < l) { while (k < l) { if (s[k] == s[l]) { s2 += s[l]; subscript = --l; k++; r2++; flag = 1; break; } l--; flag = 0; } if (!flag) { l = subscript; k++; } } int l1 = s1.size(), l2 = s2.size(); s1 = l2 > l1 ? s2 : s1; if (i >= k && i > j) { std::string s = s1; std::reverse(s.begin(), s.end()); s1 += s; r1--; } else if (k > i && k > l) { std::string s = s1; std::reverse(s.begin(), s.end()); s1 += s; r2--; } else { std::string s = s1; std::reverse(s.begin(), s.end()); s1 += str[l1 >= l2 ? i : k]; s1 += s; } r1 *= 2; r1 = i > j ? r1 : r1 - 1; r2 *= 2; r2 = k > l ? r2 : r2 - 1; r1 = l1 >= l2 ? r1 : r2; std::cout << r1 << std::endl; return s1; } }; int main() { Solution solve; std::string str = "abcda"; std::cout << str << std::endl; std::cout << solve.LPS(str) << std::endl; getchar(); return 0; }
最開始我想到的辦法是通過反轉s,得到字符串s‘,然後把問題轉化成求LCS,但我發現不符合書上要求。但看樣子,Leetcode的問題可以用這個方法解決。dp解法我還不會。。。沒得到最優子結構,所以推不出遞歸式...emmm...但我的這個算法可以解決書上的這個問題,平均情況是很快的:我估計能在O(nlgn)以內,最好情況下為:O(n);但最壞情況下,比如:abcdef這類的就是O(n2)。
LPS(最長回文子序列)