给定一个无序的整数数组,找到其中最长上升子序列的长度。
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
1,动态规划,(本题动态规划是比较好理解的,但显然效率比较低)
int lengthOfLIS(vector<int>& nums) {
int len=nums.size();
int maxlen=0;
//if(len==0) return 0;
//if(len==1) return 1;
vector<int> dp(len,1);
for(int i=0;i<len;i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i])
dp[i]=max(dp[i],dp[j]+1);
}
maxlen=max(maxlen,dp[i]);
}
return maxlen;
}
dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。
当时作此题时,dp数组习惯初始化为0.,结果一直不对,比结果少一,。后来参考了,才知道**dp需要初始化为1,**这样进行理解,不管整体结果,本身当前值就是一个最小子序列,长度为1。
时间复杂度 O(N^2)。
2,二分查找(真的很难想到,也不好理解)(在安利一次啊,不明白流程如何操作循环的,去debug一下l)
纸牌方法解释此题
每次处理一张扑克牌不是要找一个合适的牌堆顶来放吗,牌堆顶的牌不是有序吗,这就能用到二分查找了:用二分查找来搜索当前牌应放置的位置。
int lengthOfLIS(vector<int>& nums) {
int len=nums.size();
vector<int> res(len);
int maxlen=0;
//for(int num : nums){
//int num=nums[i];
//按照左侧边界进行二分查找
for(int i=0;i<len;i++){
//要处理的扑克牌
int left=0,right=maxlen;
while(left<right){
int mid=(left+right)/2;
if(res[mid]<nums[i])
left=mid+1;
else
right=mid;
}
/*********************************/
// 没找到合适的牌堆,新建一堆
if(maxlen==left)
maxlen++;
// 把这张牌放到牌堆顶
res[left]=nums[i];
}
return maxlen;
}
int main() {
vector<int> nums{ 6,3,5,10,11,2,9,14,13,7,4,8,12 };
lengthOfLIS(nums);
return 0;
}