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?
Credits:
Special thanks to @pbrother for adding this problem and creating all test cases.
这道题给了我们一堆大小不一的信封,让我们像套俄罗斯娃娃那样把这些信封都给套起来,这道题实际上是之前那道Longest Increasing Subsequence的具体应用,而且难度增加了,从一维变成了两维,但是万变不离其宗,解法还是一样的,首先来看DP的解法,这是一种brute force的解法,首先要给所有的信封按从小到大排序,首先根据宽度从小到大排,如果宽度相同,那么高度小的再前面,这是STL里面sort的默认排法,所以我们不用写其他的comparator,直接排就可以了,然后我们开始遍历,对于每一个信封,我们都遍历其前面所有的信封,如果当前信封的长和宽都比前面那个信封的大,那么我们更新dp数组,通过dp[i] = max(dp[i], dp[j] + 1)。然后我们每遍历完一个信封,都更新一下结果res,参见代码如下;
解法一:
class Solution { public: int maxEnvelopes(vector<pair<int, int>>& envelopes) { int res = 0, n = envelopes.size(); vector<int> dp(n, 1); sort(envelopes.begin(), envelopes.end()); for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { if (envelopes[i].first > envelopes[j].first && envelopes[i].second > envelopes[j].second) { dp[i] = max(dp[i], dp[j] + 1); } } res = max(res, dp[i]); } return res; } };
我们还可以使用二分查找法来优化速度,我们首先要做的还是给信封排序,但是这次排序和上面有些不同,信封的宽度还是从小到大排,但是宽度相等时,我们让高度大的在前面。那么现在问题就简化了成了找高度数字中的LIS,完全就和之前那道Longest Increasing Subsequence一样了,所以我们还是使用之前那题解法来做,参见代码如下:
解法二:
class Solution { public: int maxEnvelopes(vector<pair<int, int>>& envelopes) { vector<int> dp; sort(envelopes.begin(), envelopes.end(), [](const pair<int, int> &a, const pair<int, int> &b){ if (a.first == b.first) return a.second > b.second; return a.first < b.first; }); for (int i = 0; i < envelopes.size(); ++i) { int left = 0, right = dp.size(), t= envelopes[i].second; while (left < right) { int mid = left + (right - left) / 2; if (dp[mid] < t) left = mid + 1; else right = mid; } if (right >= dp.size()) dp.push_back(t); else dp[right] = t; } return dp.size(); } };
既然可以用二分查找法,那么使用STL的自带函数lower_bound也没啥问题了,参见代码如下:
解法三:
class Solution { public: int maxEnvelopes(vector<pair<int, int>>& envelopes) { vector<int> dp; sort(envelopes.begin(), envelopes.end(), [](const pair<int, int> &a, const pair<int, int> &b){ if (a.first == b.first) return a.second > b.second; return a.first < b.first; }); for (int i = 0; i < envelopes.size(); ++i) { auto it = lower_bound(dp.begin(), dp.end(), envelopes[i].second); if (it == dp.end()) dp.push_back(envelopes[i].second); else *it = envelopes[i].second; } return dp.size(); } };
类似题目:
Longest Increasing Subsequence
参考资料:
https://leetcode.com/discuss/106836/simple-dp-solution
https://leetcode.com/discuss/106838/c-dp-version-time-o-n-2-space-o-n
https://leetcode.com/discuss/106888/java-answer-n-lg-n-time-using-binary-search
LeetCode All in One 题目讲解汇总(持续更新中...)