【LeetCode】#5 Longest Palindromic Substring
2017-02-02 22:26
423 查看
LeetCode 题目,原题链接 https://leetcode.com/problems/longest-palindromic-substring/。
问题描述:找到字符串中最长回文子串。
参考:http://articles.leetcode.com/longest-palindromic-substring-part-i/,http://articles.leetcode.com/longest-palindromic-substring-part-ii。
按照深入程度,解决方法如下。
但是,结果就是这么简单吗?这样想当然简单了。考虑,
解决方法是考虑相同子串的位置,如在
这个方法的时间复杂度是 O(n2),但是最内层循环有
空间复杂度是 O(n)。
用一二维数组
注意,中间点可能是一个字符也有可能是两个字符,如
问题描述:找到字符串中最长回文子串。
参考:http://articles.leetcode.com/longest-palindromic-substring-part-i/,http://articles.leetcode.com/longest-palindromic-substring-part-ii。
按照深入程度,解决方法如下。
方法一
猜想:回文就是正着读、反着读结果都是一样的字符串。那么把字符串给反过来,得到一个新字符串,比较原字符串与新字符串的最长相同子串就能得到结果。如S="fabcba"与
S="abcbaf"相同部分为
"abcba",所以
"abcba"是
S中的最长回文子串。
但是,结果就是这么简单吗?这样想当然简单了。考虑,
T="abcdba"与
T'="abdcba",它们最长相同子串是
"ab",但是这东西不是回文。这个个例问题出在了将不同位置上的最长相同子串当做了回文。
解决方法是考虑相同子串的位置,如在
S与
S'自身长度为
size=6,最长相同子串长度为
len=5,子串在
S与
S'中的位置分别为
p=1与
p'=0,存在这样的关系
(size-1)-(p+len-1)=p'。
#include <iostream> #include <algorithm> #include <string> using namespace std; string longestPalindromeReverse(const string &s) { int size = s.size(); string r = s; std::reverse(r.begin(), r.end()); int longestLength = 1; int longestIndex = 0; for (int len = 1; len < size + 1; ++len) { for (int i = 0; i < size - len + 1; ++i) { string sub = s.substr(i, len); int p = i; int p_prime = r.find(sub); if (p_prime != string::npos && (size - 1) - (p + len - 1) == p_prime) { if (longestLength < len) { longestLength = len; longestIndex = i; } } } } return s.substr(longestIndex, longestLength); } int main() { cout << longestPalindromeReverse("zeusnilemacaronimaisanitratetartinasiaminoracamelinsuez") << endl; return 0; }
这个方法的时间复杂度是 O(n2),但是最内层循环有
find函数,非常耗时间。所以被 LeetCode 以
Time Limit Exceeded为理由拒绝了。
空间复杂度是 O(n)。
方法二
动态规划的方法,动态规划的套路是用一个多维的数组保存中间结果,在计算时使用中间结果加速计算。所以动态规划的空间复杂度一般比较大。用一二维数组
table保存中间结果,
table[i][j]表示
[i, j]的子串是否是回文。
#include <iostream> #include <algorithm> #include <string> using namespace std; string longestPalindromeDP(const string &s) { int longestBegin = 0; int longestLength = 1; bool table[1000][1000] = {false}; for (int i = 0; i < s.size(); ++i) { table[i][i] = true; } for (int i = 0; i < s.size() - 1; ++i) { if (s[i] == s[i + 1]) { table[i][i + 1] = true; longestBegin = i; longestLength = 2; } } for (int len = 3; len < s.size() + 1; ++len) { for (int i = 0; i < s.size() - len + 1; ++i) { if (table[i + 1][i + len - 2] == true && s[i] == s[i + len - 1]) { table[i][i + len - 1] = true; longestLength = len; longestBegin = i; } } } return s.substr(longestBegin, longestLength); } int main() { cout << longestPalindromeDP("zeusnilemacaronimaisanitratetartinasiaminoracamelinsuez") << endl; return 0; }
方法三
暴力搜索,找到回文所有可能的中间点,从中间点处向两侧扩展,搜索完所有的可能性,就能找到最长回文子串。注意,中间点可能是一个字符也有可能是两个字符,如
aba、
abba。
#include <iostream> #include <algorithm> #include <string> using namespace std; string expandArroundCenter(const string &s, int begin, int end) { int length = s.size(); int l = begin - 1, r = end + 1; while (l >= 0 && r <= length - 1 && s[l] == s[r]) { --l; ++r; } return s.substr(l + 1, r - 1 - l); } string longestPalindromeSimple(const string &s) { int length = s.size(); if (length == 0) return ""; string longest = s.substr(0, 1); int longestLength = 1; int i = 0; for (i = 0; i < length - 1; ++i) { string p1 = expandArroundCenter(s, i, i); if (p1.size() > longestLength) { longestLength = p1.size(); longest = p1; } if (s[i] == s[i + 1]) { string p2 = expandArroundCenter(s, i, i + 1); if (p2.size() > longestLength) { longestLength = p2.size(); longest = p2; } } } return longest; } int main() { cout << longestPalindromeSimple("abacdgfdcaba") << endl; return 0; }
方法四
利用回文的对称性缩减计算时间。这个方法叫做Manacher’s Algorithm。维基百科上就是这个方法。
#include <iostream> #include <algorithm> #include <string> using namespace std; string preProcess(const string &s) { int n = s.size(); if (n == 0) return "^$"; string ret = "^"; for (int i = 0; i < n; ++i) { ret.append("#").append(s.substr(i, 1)); } ret.append("#$"); return ret; } string longestPalindrome(const string &s) { string T = preProcess(s); int n = T.size(); int C = 0, R = 0; int* P = new int ; for (int i = 1; i < n - 1; ++i) { int i_mirror = 2 * C - i; P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0; while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) { ++P[i]; } if (i + P[i] > R) { C = i; R = i + P[i]; } } int longestLength = 0, longestIndex = 0; for (int i = 1; i < n - 1; ++i) { if (P[i] > longestLength) { longestLength = P[i]; longestIndex = i; } } delete[] P; return s.substr((longestIndex - 1 - longestLength)/2, P[longestIndex]); } int main() { cout << longestPalindrome("abacdgfdcaba") << endl; return 0; }
相关文章推荐
- leetcode编程记录5 #5 Longest Palindromic Substring
- [Leetcode] #5 Longest Palindromic Substring
- Longest Palindromic Substring_Leetcode_#5
- LeetCode题库解答与分析——#5.最长回文子串LongestPalindromicSubstring
- LeetCode题解 #5 Longest Palindromic Substring
- 【一天一道LeetCode】#5 Longest Palindromic Substring
- Leetcode练习 #5 Longest Palindromic Substring
- 【一天一道LeetCode】#5 Longest Palindromic Substring
- Longest Palindromic Substring leetcode java
- LeetCode: Longest Palindromic Substring
- [LeetCode] Longest Palindromic Substring
- [LeetCode] Longest Palindromic Substring - O(n)
- LeetCode题目 5. Longest Palindromic Substring
- LeetCode Longest Palindromic Substring
- 【leetcode】Longest Palindromic Substring
- 【Leetcode】Longest Palindromic Substring
- [leetcode]Longest Palindromic Substring @ Python
- Leetcode日志--LongestPalindromicSubstring
- Leetcode Longest Palindromic Substring
- #leetcode#Longest Palindromic Substring