8.5分钟学会动态规划里的最长上升子序列和最长连续递增序列

啊?我怎么起了个这么长的题目,没办法啊,文采不够,只能字数来凑了。相信我,这篇一定不会让你失望,如果让你失望了,实在是抱歉,那一定是我没做好,我一定再接再厉。

言归正传哈,咱们下面去聊,毕竟这是一篇技术博客,还是要严肃点吧。

来,看两道题:

第一题:给你一个整数数组 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。

第二题:给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。

示例 1: 输入:nums = [1,3,5,4,7] 输出:3 解释:最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。

怎么样?看出两道题目的相同点和不同点了没?啊?什么,你没看到?不会吧!其实我看第一遍的时候也没看出来,再看一遍?什么?找到了?你真棒,来,我们一起说一说共同点:都是求最长递增子序列的长度,同学们真的是慧眼啊;那么不同的地方呢?来,小明,你来说,第一题是求最长递增子序列,不要求连续;而第二题必须是连续最长递增子序列。哇塞,不愧是大名鼎鼎的小明同学啊。

那么谁知道,递增序列的万能推导公式是什么呢?谁来说说,来,小红,你来说,

如果是不连续的求递增序列的长度,就用这个公式:

for(int i=1;i<nums.size();i++)//遍历较大的值
    for(int j=0;i<i;j++)//遍历较小的值
    {
        if(nums[i]>nums[j])
        {
            dp[i]=max(dp[i],dp[j]+1)
        }
    }

如果是连续的求递增子序列的长度,就用这个公式:

for(int i=1;i<nums.size();i++)
{
    if(nums[i]>nums[i-1])
    {
        dp[i]=max(dp[i],dp[i-1]+1)
    }
}

小红你真棒,说对了。

“老师,我是新来的,不明白为什么要这么写”,小刚说。

谁能来给小刚同学解释一下每一行的代码的意思啊?

“我来吧”,小光爽朗的说。

“好,那就掌声有请小光来给咱们大家解释他们的意思。”

第一个程序:

for(int i=1;i<nums.size();i++)//是对整个Nums数组进行遍历,从第2个数字开始;

for(int j=0;i<i;j++)//也是对整个nums数组进行遍历,不过j永远是在[0-i)的范围内遍历;

if(nums[i]>nums[j])//专门寻找i比j大的那个数字
        {
            dp[i]=max(dp[i],dp[j]+1)//一旦找到,就拿第i个数字的序列长度和第j个数字的序列长度+1比较大小,谁大就选谁
        }

第二个程序:

for(int i=1;i<nums.size();i++)//从第2个数字开始遍历
{
    if(nums[i]>nums[i-1])//一旦找到第i个数字比第i-1个数字大
    {
        dp[i]=max(dp[i],dp[i-1]+1)//立马在现有的序列长度的基础上加1
    }
}

大家说小光解释的好不好啊?真好,掌声表扬一下,小刚你听懂了嘛?

“嗯,听懂了,谢谢小光!”(脸上露出洋溢的笑容)

谁能把这个程序的完整代码写一下呀?

好,王彤举手了,你来写第一个,董莉莉举手了,你来写第二个

第一个程序:

#include <iostream>
#include <vector>
using namespace std;
int lengthOfLIS(vector<int>& nums) {
        vector<int> dp(nums.size(),1);
        int result=0;
        for(int i=1;i<nums.size();++i)
        {
            for(int j=0;j<i;++j)
            if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
            if(dp[i]>result) result=dp[i];
        }
        return result;
}
int main()
{
    vector<int> num={1,3,5,4,7};
    int ret=lengthOfLIS(num);
    cout<<"ret="<<ret<<endl;
    return 0;
}

运行结果是多少?4,那就没问题。

第二个程序

#include <iostream>
#include <vector>
using namespace std;
int lengthOfLIS(vector<int>& nums) {
        
        vector<int> dp(nums.size(),1);
        int result=0;
        for(int i=1;i<nums.size();++i)
        {
            
            if(nums[i]>nums[i-1]) 
            dp[i]=max(dp[i],dp[i-1]+1);
            if(dp[i]>result) 
            result=dp[i];
        }
        return result;
}
int main()
{
    vector<int> num={1,3,5,4,7};
    int ret=lengthOfLIS(num);
    cout<<"ret="<<ret<<endl;
    return 0;

}

书写完毕,这个运行结果是多少?3,没问题。

亲爱的,你学会了嘛?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值