Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101]
, therefore the length is 4.
Note:
给定未排序的整数数组,找到最长的增加子序列的长度。
注意:
对于这道题,题目是一道比较经典的LIS问题,即最长上升子序列问题。
这种问题的解法很多,逐一说明太过麻烦。这里说一种利用C++内的STL的方法:lower_bound
:
lower_bound( begin,end,num):
从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。在这道题的解法上,我们对定义的res数组利用lower_bound进行遍历,找到比nums[i]小的元素:
具体原理在于,在对nums的遍历的过程中,我们每次是找到res中第一个比nums[i]小的元素,之所以对它更新,是为了保证对之后新的res的创建。
当然,最后的结果中,res并不是正确的序列,但是长度是正确的。
为何是不正确的:(这里使用LeetCode的discussion的讲解)
For example, if
nums = [5,6,7,1,2,8,3,4,0,5,9]
then after we prcoess the 7:
S = [5,6,7]
after w process the 2:
S = [1,2,7]
after we process the 8:
S = [1,2,7,8]
Then we process the 3:
S = [1,2,3,8]
We process the 4:
S = [1,2,3,4]
and now the next three elements:
S = [0,2,3,4,5,9]
S is not the actual subsequence, but it is the right length (end ends in the right number).
而之所以最后的长度是可行的,是lower_bound是找到第一个比nums[i]小的,而不会对res的最大长度造成影响。而自所以要对res进行更改,是为了使得可能存在的比当前res值要小的序列的记录,以记录更长的LIS,比如:
nums = [5,6,1,2]
一开始,res = [5, 6]
,长度为2
而1的加入,有:res = [1,6]
2的加入,有:res = [1,2]
这时,长度也是2。
而假如nums = [5,6,1,2,3]
步骤一样,这时,res = [1,2,3]
,最大长度就是3了。
关于lower_bound( )和upper_bound( )的常见用法
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size() == 0)
return 0;
vector<int> res;
for(auto &n : nums){
auto itr = lower_bound(res.begin(), res.end(), n);
if(itr == res.end())
res.push_back(n);
else
*itr = n;
}
return res.size();
}
};