当前位置: 首页 > article >正文

动态规划part01

文章参考来源代码随想录

理论基础

适用范围

如果某一问题有很多重叠子问题,使用动态规划是最有效的。

与贪心算法的区别

动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的

状态转移公式(递推公式)是很重要,但动规不仅仅只有递推公式。

动规五部曲

1.确定dp数组(dp table)以及下标的含义

2.确定递推公式

3.dp数组如何初始化

4.确定遍历顺序

5.举例推导dp数组

debug:

找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的

以及反思:

  • 这道题目我举例推导状态转移公式了么?
  • 我打印dp数组的日志了么?
  • 打印出来了dp数组和我想的一样么?

509. 斐波那契数

动规五部曲:

1.确定dp数组以及下标的含义:第i个位置的斐波那契值为dp[i];

2.确定递推公式:dp[i]=dp[i-1]+dp[i-2];

3.dp数组如何初始化:斐波那契数列初始前两个位置为0,1;

4.确定遍历顺序:因为递推是从前往后因此这里从前往后遍历;

5.举例推导dp数组:

按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:

0 1 1 2 3 5 8 13 21 34 55

class Solution {
public:
    int fib(int n) {
        if(n<=1)return n;
        vector<int>dp(n+1);
        dp[0]=0;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
};

特别情况 :

当n小于等于1时这里不用递归公式,因为这两个本来就有初始化的,所以直接输出即可

优化:

我们只需要维护两个数值就可以了,不需要记录整个序列,因此这里可以用sum来记录dp[i-1]+dp[i-2]的值,然后更新dp[i-2]为dp[i-1],dp[i-1]为sum。

70. 爬楼梯

动规五部曲:

1.确定dp数组以及下标的含义:能爬到第i个位置的方法为dp[i];

2.确定递推公式:dp[i]=dp[i-1]+dp[i-2];

3.dp数组如何初始化:前两个台阶能爬的方法初始化为1,2;

4.确定遍历顺序:因为递推是从前往后因此这里从前往后遍历;

5.举例推导dp数组:

当n=3时,应该是第一个台阶方法数+第二个的,结果是1+2=3成立

dp数组0 1 2 3

class Solution {
public:
    int climbStairs(int n) {
        if(n==1)return n;
        vector<int>dp(n+1);
        dp[1]=1;
        dp[2]=2;
        for(int i=3;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
};

特别情况 :

当n等于1时这里不用递归公式,因为第一个台阶只有一种方法,所以直接输出即可

优化:

我们只需要维护两个数值就可以了,不需要记录整个序列,因此这里可以用sum来记录dp[i-1]+dp[i-2]的值,然后更新dp[i-2]为dp[i-1],dp[i-1]为sum。

746. 使用最小花费爬楼梯

动规五部曲:

1.确定dp数组以及下标的含义:能爬到第i个位置并由此向上爬的最小花费为dp[i](包括该位置的花费,因为这里我们要cost是不包括最后一个台阶的);

2.确定递推公式: dp[i]=min(dp[i-1],dp[i-2])+cost[i];

3.dp数组如何初始化:能爬到前两个台阶(0,1)并由此向上爬的最小花费初始化为cost[0],cost[1];

4.确定遍历顺序:因为递推是从前往后因此这里从前往后遍历;

5.举例推导dp数组:

具体cost具体分析

拿示例2:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] ,来模拟一下dp数组的状态变化,如下

需要注意的点 :

这里dp大小初始化为cost大小,爬到最后一个台阶的最小花费实际上就是爬到倒数第一个或者第二个台阶并由此向上爬的最小花费

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        vector<int>dp(cost.size());
        dp[0]=cost[0];
        dp[1]=cost[1];
        for(int i=2;i<cost.size();i++){
            dp[i]=min(dp[i-1],dp[i-2])+cost[i];
        }
        return min(dp[cost.size()-1],dp[cost.size()-2]);
    }
};


http://www.kler.cn/a/429375.html

相关文章:

  • 基于 K-Means 聚类分析实现人脸照片的快速分类
  • 【机器学习】制造业转型:机器学习如何推动工业 4.0 的深度发展
  • level(三) filterblock
  • 内联变量(inline variables):在多个文件中共享全局常量
  • JAVA安全—JWT攻防Swagger自动化Druid泄露
  • WORD转PDF脚本文件
  • LLM - 01_了解LangChain和LangChain4J
  • 【工具变量】上市公司企业研发不确定性数据(2013-2023年)
  • 热更新xLua实践(xLua背包)
  • 单链表(C语言版本)
  • Hermes engine on React Native 0.72.5,function无法toString转成字符串
  • VUE3学习二
  • 使用docker让项目持续开发和部署
  • 【NLP 12、深度学习15条调参经验】
  • 【Golang】Go语言编程思想(四):测试与性能调优
  • 字符串知识
  • C语言专题之结构体的使用
  • 锐捷网络设备常用命令(交换机、路由器)
  • “掌握AWD:解密全轮驱动的终极性能“
  • amazon亚马逊滑动识别验证码
  • Python Web 开发:FastAPI 依赖注入与中间件应用
  • PHP期末复习(通过30道填空题梳理知识点)
  • 十六,Spring Boot 整合 Druid 以及使用 Druid 监控功能
  • 零基础微信小程序开发——WXML 模板语法之事件绑定(保姆级教程+超详细)
  • 嵌入式驱动开发详解4(内核定时器)
  • sessionStorage对象--JSON数组--使用花括号{}直接定义对象--丝滑小连招:----客户端缓存之一