1.题目如下:
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
进阶:
你能将算法的时间复杂度降低到 O(n log(n)) 吗?
2.代码如下:
class Solution {
public:
//思路一:动态规划
/*
D[i]=max(D[0]~D[i-1])+1 s[j]<s[i]
*/
/*
int lengthOfLIS(vector<int>& nums) {
vector<int> resTemp(nums.size(),1);
resTemp[0]=1;
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
resTemp[i]=max(resTemp[j]+1,resTemp[i]);
}
}
}
return *max_element(resTemp.begin(),resTemp.end());
}
*/
//思路二:使用贪心算法+二分法:O(nlogn)
/*
为了使递增序列更长,那么希望每一次增长序列的时候末尾的数字最小越好,那么维护一个数组d,这个数组是严格递增的
d[i]表示长度为i的最长上升子序列的末尾元素的最小值,用len记录目前最长上升子序列的长度,起始时len为1,d[1]=nums[0]。
更新时,如果新增元素小于递增序列末尾元素,则用二分法找到最小的大于该元素的数并替代
*/
int lengthOfLIS(vector<int>& nums) {
int len=1,n=nums.size();
if (n==0) {
return 0;
}
vector<int> d(n+1,0);
d[len] = nums[0];
for (int i=1;i<n;++i) {
if (nums[i]>d[len]) {
d[++len]=nums[i];
}
else {
// 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
int l=1,r=len,pos=0;
while (l<=r) {
int mid=(l+r)/2;
if (d[mid]<nums[i]) {
pos=mid;
l=mid+1;
}
else {
r=mid-1;
}
}
d[pos+1]=nums[i];
}
}
return len;
}
};