题目:
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example, Given [10, 9, 2, 5, 3, 7, 101, 18]
,
The longest increasing subsequence is [2, 3, 7, 101]
, therefore the length is 4
. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
解答:
寻找最长上升子序列(LIS),最基本的方法是动态规划。转移方程为 dp[i] = max{dp[j]} + 1 ( -1< j < i && nums[j] < nums[i])。
解释也非常直观:dp[i] 表示如果取得当前 i 元素,所能达到的最长 LIS。如果需要打印出此序列,仅需要保存上一个元素。
class Solution { public: int lengthOfLIS(vector<int>& nums) { int size = nums.size(); if (size <= 1) return size; vector<int> dp(size, 1); int maxlen; for (int i = 1; i < size; i++) { maxlen = 0; for (int j = 0; j < i; j++) { if (nums[j] < nums[i] && maxlen < dp[j]) maxlen = dp[j]; } dp[i] = maxlen + 1; } maxlen = 0; for (int i = 0; i < size; i++) { if (dp[i] > maxlen) maxlen = dp[i]; } return maxlen; } };
如果要修改到 O(n log n) time complexity?贪心法 + 二分搜索。
增加一条辅助的顺序(ordered)栈(队列……完成任务就好),保存尽可能长的LIS。入栈的要求为:
直观理解:对于 x 和 y,如果 x < y 且 stack[y] < stack[x],用 stack[x] 替换 stack[y],此时的最长序列长度没有改变,但序列继续变长的''潜力''增大,这就是贪心的目标。
举例:原序列为1,5,8,3,6,7
开始1,5,8相继入栈,此时读到3,用3替换5,得到1,3,8;再读6,用6替换8,得到1,3,6;再读7,得到最终栈为1,3,6,7。最长递增子序列为长度4
但是这个方法,有一个很大的缺陷:只能保证序列长度的正确性,不能保证栈中就是正确的序列。
举例:原序列为1,5,8,2,栈内最后是 1,2,8 不是正确的序列。
分析一下,我们可以看出,虽然有些时候这样得不到正确的序列,但最后算出来的个数是没错的,为什么呢?
当a[i]>top时,总个数直接加1,这肯定没错;但当a[i]<top时呢? 这时a[i] 会替换栈里面的某一个元素,总个数不变。如果求具体序列,还是动态规划比较好。
class Solution { public: int lengthOfLIS(vector<int>& nums) { vector<int> LIS; for (int i = 0; i < nums.size(); i++) { if (LIS.size() == 0 || LIS[LIS.size() - 1] < nums[i]) { LIS.push_back(nums[i]); } else { int l = 0, r = LIS.size() - 1; while (l < r) { int m = (l + r) / 2; if (LIS[m] >= nums[i]) { r = m; } else { l = m + 1; } } LIS[l] = nums[i]; } } return LIS.size(); } };
https://en.wikipedia.org/wiki/Longest_increasing_subsequence
http://blog.csdn.net/yorkcai/article/details/8651895
https://leetcode.com/discuss/67888/c-clean-o-nlogn-code-using-binary-search