动态规划-线性dp(2)-最长上升子序列

最长上升子序列是动态规划的中比较常见的题目,我第一次听最长上升子序列,浙大陈越姥姥的课程中听到的。她分析了用不同的方法去解决该问题。
题目如下:
Acwing-895
Leetcode-300

这两道题目都是最长上升子序列的题目:很经典
按照以往的惯例,还是去用闫氏DP分析法去分析:
DP问题思考方式

状态表示f[i]: 如何理解状态表示呢?能用一维度解决,坚决不使用二维。毕竟还是要从实际问题除法
集合:f[i]是状态数组,表示的是:以i结尾的最长上升子序列的长度
属性:以i结尾的最长上升自序里的长度的最大值

状态计算: 这里就是集合的划分:
这里先用口述去说明一下:如何从字面上去理解。
如果我的一段序列是,单调递减的:那么显然长度只有1,也就是固定到第i位置的单个元素的长度
比如:3 2 1.那么如果第i个位置(其实就是第三个位置),那么显然长度只有i啊
如果我的一段序列是,单调递增的:那么说明,以i结尾的状态数组的前面,存在一个索引位置j,使得arr[j]<arr[i],那么长度就要增加一位。还是要从全局除法,我们的目的是:讲一个大的问题分成若干个子问题,那我现在就分了啊,我将f[i]分成了f[j]+1.f[j]就是我们所有求子问题,f[j]再去求出以j结尾得最长上升子序列的最大值。
那么我们从字面上可以得出状态方程为:dp[i]=max(dp[i],d[j]+1)

这里画一个集合状态图去进行考虑:
在这里插入图片描述

补充一句,我们应该从整体上考虑,只要在集合上不重不漏,那么应该是正确的。
第一题代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int arr[N],dp[N];
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        dp[i]=1;//以第i结尾的最长上升子序列
        for(int j=0;j<i;j++){
            if(arr[j]<arr[i]) dp[i]=max(dp[i],dp[j]+1);
        }
    }
    int res=0;
    for(int i=1;i<=n;i++) res=max(res,dp[i]);
    cout<<res;
    return 0;
}

第二题代码如下(其实是一摸一样的题目),但是力扣的形式是写一个函数:
这里引入一个小技巧,求一个数组最大值的时候,可以直接调用库函数,省心省力。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        
        int len=nums.size();
        if(len==0) return 0;
        auto f=vector<int>(len,1);//状态数组,初始化的时候全部初始化为1
        //边界处理
        
        for(int i=1;i<len;i++){
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]) f[i]=max(f[i],f[j]+1);
            }
        }
        //c11直接库函数返回数组元素的最大值
        return *max_element(f.begin(),f.end());
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值