题目
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?
解题之法
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp;
for (int i = 0; i < nums.size(); ++i) {
int left = 0, right = dp.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (dp[mid] < nums[i]) left = mid + 1;
else right = mid;
}
if (right >= dp.size()) dp.push_back(nums[i]);
else dp[right] = nums[i];
}
return dp.size();
}
};```
###分析
下面我们来看一种优化时间复杂度到O(nlgn)的解法,这里用到了二分查找法,所以才能加快运行时间。
思路是先建立一个空的dp数组,然后开始遍历原数组,对于每一个遍历到的数字,我们用二分查找法在dp数组找第一个不小于它的数字,如果这个数字不存在,那么直接在dp数组后面加上遍历到的数字,如果存在,则将这个数字更新为当前遍历到的数字,最后返回dp数字的长度即可,特别注意的是,dp数组的值可能不是一个真实的LIS。
下面我们来看比较tricky的解法,利用到了C++中STL的lower_bound函数,lower_bound返回数组中第一个不小于指定值的元素。
跟上面的算法类似,我们还需要一个一维数组v,然后对于遍历到的nums中每一个元素,找其lower_bound,如果没有lower_bound,说明新元素比一维数组的尾元素还要大,直接添加到数组v中。
如果有lower_bound,说明新元素不是最大的,将其lower_bound替换为新元素,这个过程跟二分查找法的部分实现相同功能,最后也是返回数组v的长度,注意数组v也不一定是真实的LIS。
```C++
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> v;
for (auto a : nums) {
auto it = lower_bound(v.begin(), v.end(), a);
if (it == v.end()) v.push_back(a);
else *it = a;
}
return v.size();
}
};