链接:
题意:
子序列:任意删除元素但不改变顺序
求整数数组 nums
得最长严格递增子序列的长度
解:
DP[i]
记录的是长度 i 位的严格递增子序列的最后一位的最小值
ans为目前最长严格递增子序列的长度(其实用dp.size()
更好,自行体会,懒得改了)
遍历数组:
当前数字大于DP[ans-1] 下标0起
时,放入序列尾部
当前数字小于DP[ans-1]
时,找到一个最大的小于它的数字DP[t]
<now,替换该数字的下一个位置DP[t+1]=now
原理是,在长度 LG 的情况下,最后一个数字越小,最终的长度理论上越长,所以把小的数字放到符合条件的最靠前的位置,即前一个数字是最后一个小于它的数字
普通双循环应该是O(N^2)
,后面用了一个upper_bound二分查找应该有O(N log(N))
了吧
(不过时间跑出来好像和加了编号1
的break一样,XD
)
执行用时:8 ms, 在所有 C++ 提交中击败了93.48%的用户
内存消耗:10.1 MB, 在所有 C++ 提交中击败了87.88%的用户
实际代码:
普通双循环:
#include<bits/stdc++.h>
using namespace std;
int lengthOfLIS(vector<int>& nums)
{
int ans=1,lg=nums.size();
vector<int>dp(lg+1);dp[0]=nums[0];
for(int index=1;index<lg;index++)
{
if(dp[ans-1]<nums[index])
{
dp[ans++]=(nums[index]);
}
else
{
for(int jndex=ans-1;jndex>=0;jndex--)
{
if(jndex==0) dp[jndex]=min(dp[jndex],nums[index]);
else
{
if(dp[jndex-1]<nums[index])
{
dp[jndex]=min(dp[jndex],nums[index]);
break;//我在这里 - 编号1
}
}
}
}
}
//cout<<ans<<endl;
return ans;
}
int main()
{
vector<int> nums;int temp;
while(cin>>temp)
{
nums.push_back(temp);
}
int ans=lengthOfLIS(nums);
cout<<ans<<endl;
return 0;
}
upper_bound:
#include<bits/stdc++.h>
using namespace std;
int lengthOfLIS(vector<int>& nums)
{
int ans=1,lg=nums.size();
vector<int>dp(lg+1);dp[0]=nums[0];
vector<int>::iterator it=dp.begin(),upper;it++;
for(int index=1;index<lg;index++)
{
if(dp[ans-1]<nums[index])
{
dp[ans++]=(nums[index]);
it++;
}
else
{
upper=upper_bound(dp.begin(),it,nums[index]);
if(upper==it||upper==dp.end()) continue;//没找到
if(upper==dp.begin()) *upper=min(*upper,nums[index]);
else if(*(upper-1)<nums[index]) *upper=min(*upper,nums[index]);
}
}
//cout<<ans<<endl;
return ans;
}
int main()
{
vector<int> nums;int temp;
while(cin>>temp)
{
nums.push_back(temp);
}
int ans=lengthOfLIS(nums);
cout<<ans<<endl;
return 0;
}
限制:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104