300. 最长递增子序列-leetcode刷题(C++)

这篇博客介绍了如何使用C++解决LeetCode上的300题——最长递增子序列。作者首先指出,简单的递归回溯方法效率低下,然后详细阐述了动态规划的解决方案,包括无优化和使用贪心算法结合二分搜索的优化方法。文中提供了两种方法的执行时间和内存消耗对比。
摘要由CSDN通过智能技术生成

一、题目

300. 最长递增子序列

二、分析

  1. 采用递归+回溯可以求出全部的子序列,但是时间复杂度太高了。
  2. 采用动态规划做:定义一个DP[i]数组,记录从0到i的最长递增子序列。
nums = [10,9,2,5,3,7,101,18]
dp[0] = 1;
dp[1] = 1;
dp[2] = 1;
dp[3] = 2;
...
对于dp[i],需要向前查找所有的dp数组值,为什么呢?
以数值5为例:要求dp[3],需要遍历他前边的所有递增子序列长度,然后与5进行对比。
1、如果前边 有某个递增子序列 的最右侧值(即max)小于5,例如 "2" 这个子序列,构成新的子序列:"2, 5",所以dp[3] = dp[2] + 1;
2、如果前边 没有任何递增子序列 的最右侧值(即max)小于5,说明前边没有可以和5构成子序列的,那么自身构成子序列"5",则 dp[3]=1.
...
dp[4] = dp[2] + 1 = 2;
dp[5] = dp[4] + 1 = 3; // 经历了dp[2]+1, dp[3]+1
dp[6] = dp[5] + 1 = 4; // 经历了dp[0]+1, dp[3]+1
dp[7] = dp[5] + 1 = 4; //经历了dp[0]+1, dp[3]+1
  1. 贪心算法 + 二分搜索:参考
以nums = [10,9,2,5,3,7,101,18, 4, 8, 6, 12] 为例
i = 0:  tail = [10];
i = 1:  tail = [9]; //找到tail中 第一个 大于9的,将其替换
i = 2:  tail = [2];
i = 3:  tail = [2, 5]; // 5 > tail[end],所以加到结尾
i = 4:  tail = [2, 3]; // 通过二分查找,找到第一个大于3的,替换
---
已经得到的上升子序列的结尾的数越小,那么遍历的时候后面接上一个数,会有更大的可能构成一个长度更长的上升子序列。所以结尾越小越好,所以要找到第一个大于3的,这样后边有更大可能构成更长的上升子序列。
比如:[2, 5], 来了一个数: 4,最长子序列还是2;但是如果是[2, 3], 最长子序列就可以是: [2, 3, 4].
---
i = 5:  tail = [2, 3, 7]; //7 > tail[end],所以加到结尾
i = 6:  tail = [2, 3, 7, 101];
i = 7:  tail = [2, 3, 7, 18]; //二分查找,18替换101
i = 8:  tail = [2, 3, 4, 18]; //二分查找,4替换7
i = 9:  tail = [2, 3, 4, 8]; //二分查找,8替换18
i = 10: tail = [2, 3, 4, 6]; //二分查找
i = 11: tail = [2, 3, 4, 6, 12]; //直接加到末尾

三、代码

  1. 无优化的动态规划解法
class Solution {
   
public:
    int lengthOfLIS(vector<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值