最初写的代码太丑陋,所以去掉了。
------------update 2018-02-05 12:46:22-------------
题目例子:
对于字串:abklmncdefg 正确答案是:7 (abcdefg) 过程是这样的:abklmn 下一个c就中断了,于是再从头开始检查还有没有更长的: abk abl abm abn abcdefg 通过匹配发现abcdefg是最长的,所以返回。
几个月之前搜过这个题,了解到这是一个dp经典题,但我当时并没有dp的概念,所以题解也没看懂...现在我再次尝试解决一下:
class Solution { public: int LargestLongSubsequence(char str[]) { int Length = (int)strlen(str); if(Length == 0) return 0; char* sub_str = new char; for(int i = Length - 1; i >= 0; i--) { char s[Length]; int k = 0; for(int j = 0; j <= i; j++) { if(str[j] < str[i] && str[j] < str[j + 1]) s[k++] = str[j]; else continue; } s[k] = ' '; //std::cout << s << std::endl; if((int)strlen(sub_str) <= (int)strlen(s)) { strcpy(sub_str,s); } } //std::cout << sub_str << std::endl; return (int)strlen(sub_str) + 1; } }
思路:最长递增子序列的最后一个字符肯定是更靠近数组的右端一些。那么这样就可以用一个外层循环从最右边开始递减,再用一个内层循环从最左边的开始递增并和外层的字符进行比较,如果满足比当前右边的小且当前的字符比后一个字符小就加入到新的字符数组中。时间复杂度O(n^2),空间复杂度O(n)。
--------------------update 2018-02-06 19:49:11---------------------
代码有bug...没考虑到如这样的字符串:abcabc,我的算法返回结果长度是 5,正确的长度为3。
正确的dp解法:
class Solution { public: int LongestIncreasingSubsequence(string str) { if(str.empty()) return 0; vector<int> dp(str.size(), 1); int res = 1; for (int i = 1; i < str.size(); i++) { for (int j = 0; j < i; j++) if (str[j] < str[i]) dp[i] = max(dp[i],dp[j] + 1); res = max(res, dp[i]); } return res; } };
时间复杂度O(n^2),空间复杂度为O(n)。
----------------update 2018-02-10 19:44:10-------------
记录一个O(nlgn)复杂度的算法:
#include <iostream> #include <vector> #include <string> using namespace std; class Solution { public: int LongestIncreasingSubsequence(string str) { if(str.empty()) return 0; vector<char> res{str[0]}; for(auto s : str) { int l = 0, r = res.size() - 1; if (res.back() < s) res.push_back(s); else { while(l < r) { int m = l + (r - l) / 2; if (res[m] < s) l = m + 1; else r = m; } res[r] = s; } } return (int)res.size(); } }; int main() { Solution solve; string str = "abklmncdefg"; cout << solve.LongestIncreasingSubsequence(str) << endl; return 0; }
算法很好,但得到的子序列并不是原来的LIS序列,长度一样。