代码随想录算法训练营第三十八天 | 动态规划基础流程

news2024/10/5 20:21:12

动态规划理论基础

代码随想录 (programmercarl.com)

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

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

大家知道动规是由前一个状态推导出来的,而贪心是局部直接选最优的,对于刷题来说就够用了。

动态规划的解题步骤

思路过程:第一步怎么得到、第二步怎么得到、第三步怎么得到…

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

一些同学可能想为什么要先确定递推公式,然后在考虑初始化呢?因为一些情况是递推公式决定了dp数组要如何初始化!

动态规划应该如何debug

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

做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果

然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。

如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。

如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。

这样才是一个完整的思考过程,而不是一旦代码出问题,就毫无头绪的东改改西改改,最后过不了,或者说是稀里糊涂的过了

509. 斐波那契数

文档讲解:代码随想录 (programmercarl.com)

视频讲解:手把手带你入门动态规划 | 对应力扣(leetcode)题号:509.斐波那契数_哔哩哔哩_bilibili

状态:想到递归,没注意到for循环,要根据动态规划的步骤来写。

思路

动规五部曲:

这里我们要用一个一维dp数组来保存递归的结果

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

    dp[i]的定义为:第i个数的斐波那契数值是dp[i]

  2. 确定递推公式

    题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];

  3. dp数组如何初始化

    题目中把如何初始化也直接给我们了

    dp[0] = 0;
    dp[1] = 1;
    
  4. 确定遍历顺序

    从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的

  5. 举例推导dp数组

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

    0 1 1 2 3 5 8 13 21 34 55

    如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。

代码

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];
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

可以发现,我们只需要维护两个数值就可以了,不需要记录整个序列

class Solution {
public:
    int fib(int N) {
        if (N <= 1) return N;
        int dp[2];
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= N; i++) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

70. 爬楼梯

文档讲解:代码随想录 (programmercarl.com)

视频讲解:带你学透动态规划-爬楼梯(对应力扣70.爬楼梯)| 动态规划经典入门题目_哔哩哔哩_bilibili

状态:没想出来。

思路

思路过程:第一步怎么得到、第二步怎么得到、第三步怎么得到…

爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。

那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。所以到第三层楼梯的状态可以由第二层楼梯 和 第一层楼梯状态推导出来,那么就可以想到动态规划了。

动规五部曲:

定义一个一维数组来记录不同楼层的状态

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

    dp[i]: 爬到第i层楼梯,有dp[i]种方法

  2. 确定递推公式

    从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来。

    首先是dp[i - 1],到i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶不就是dp[i]了么。

    还有就是dp[i - 2],到i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶不就是dp[i]了么。

    那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!所以dp[i] = dp[i - 1] + dp[i - 2] 。

    在推导dp[i]的时候,一定要时刻想着dp[i]的定义,否则容易跑偏。

  3. dp数组如何初始化

    不考虑dp[0]如何初始化,只初始化dp[1] = 1,dp[2] = 2,然后从i = 3开始递推,这样才符合dp[i]的定义。

  4. 确定遍历顺序

    从递推公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,遍历顺序一定是从前向后遍历的

  5. 举例推导dp数组

在这里插入图片描述

代码

class Solution {
public:
    int climbStairs(int n) {
        if (n <= 1) return n; // 因为下面直接对dp[2]操作了,防止空指针
        vector<int> dp(n + 1);
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) { // 注意i是从3开始的
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

可以,优化一下空间复杂度,代码如下:

class Solution {
public:
    int climbStairs(int n) {
        if (n <= 1) return n;
        int dp[3];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            int sum = dp[1] + dp[2];
            dp[1] = dp[2];
            dp[2] = sum;
        }
        return dp[2];
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

746. 使用最小花费爬楼梯

文档讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划开更了!| LeetCode:746. 使用最小花费爬楼梯_哔哩哔哩_bilibili

状态:能直接做出来。

思路

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

    使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了。

    dp[i]的定义:到达第i台阶所花费的最少体力为dp[i]

  2. 确定递推公式

    可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]

    dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。

    dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。

    那么究竟是选从dp[i - 1]跳还是从dp[i - 2]跳呢?

    一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);

  3. dp数组如何初始化

    只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。

    新题目描述中明确说了 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 从 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。所以初始化 dp[0] = 0,dp[1] = 0;

  4. 确定遍历顺序

    因为是模拟台阶,而且dp[i]由dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。

  5. 举例推导dp数组

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

    在这里插入图片描述

代码

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        vector<int> dp(cost.size() + 1);
        dp[0] = 0; // 默认第一步都是不花费体力的
        dp[1] = 0;
        for (int i = 2; i <= cost.size(); i++) {
            dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
        }
        return dp[cost.size()];
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

还可以优化空间复杂度,因为dp[i]就是由前两位推出来的,那么也不用dp数组了,C++代码如下:

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int dp0 = 0;
        int dp1 = 0;
        for (int i = 2; i <= cost.size(); i++) {
            int dpi = min(dp1 + cost[i - 1], dp0 + cost[i - 2]);
            dp0 = dp1; // 记录一下前两位
            dp1 = dpi;
        }
        return dp1;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java结合POI框架实现Excel导入

Java结合POI框架实现Excel导入 一、流程概念二、conroller中的方法三、导入成功 一、流程概念 我们需要把excel通过上传得方式导入数据库&#xff0c;需要以下几个步骤 将excel上传到服务器指定文件夹内并重命名&#xff08;upload&#xff09;获取到文件公共路径和别名路径将…

InsCode再进步,AI 辅助编程帮你打开思路

文章目录 一、前言二、使用 AI 辅助完成代码1. 基于模板创建项目2. 使用 AI 辅助开拓思路3. 使用 AI 辅助生成代码4. 使用 AI 辅助优化代码 三、InsCode AI Chat 的使用建议四、总结 一、前言 你好&#xff0c;我是小雨青年&#xff0c;一名独立开发的程序员。 在之前的文章中…

Ubuntu22.04安装PyTorch1.13.0 GPU版本

目录 一、电脑相关信息 1. 电脑显卡环境&#xff1a; 二、安装Pytorch1.13.0/cu117&#xff08;GPU版本&#xff09; 1. 准备&#xff1a;新建虚拟环境 2. 用conda在线安装pytorch1.13.0/cu117&#xff08;pytorch1.13.0 torchvision0.14.0 pytorch-cuda11.7&#xff09;…

博客管理系统前端分析

目录结构博客列表页&#xff1a;所有页面共同的样式代码&#xff1a;博客详情页博客登录页博客编辑页 目录结构 博客列表页&#xff1a; 页面效果&#xff1a; 代码&#xff1a; <!-- 博客列表页 --> <!DOCTYPE html> <html lang"en"> <head…

计算机视觉的深度学习 Lecture4:Optimization 笔记 EECS 498.008

数值计算梯度 问题是慢&#xff0c;每个都要注意做步长&#xff0c;求除法。 应该用求导方法解决。 SGD通过每次抽取一部分&#xff08;mini-batch&#xff09;来计算梯度&#xff0c;而不是遍历整个数据集来求梯度&#xff0c;大大增大了求梯度速度&#xff0c;并且性能不…

TCP 协议特性详解

TCP 协议特性总结 TCP协议特点TCP协议段格式TCP原理确认应答&#xff08;安全机制&#xff09;超时重传&#xff08;安全机制&#xff09;连接管理&#xff08;安全机制&#xff09;(面试高频题)三次握手四次挥手 滑动窗口&#xff08;效率机制&#xff09;流量控制&#xff08…

【LeetCode】数据结构题解(8)[链表中的入口节点]

链表中的入口节点 1.题目来源2.题目描述3.解题思路4.代码展示 1.题目来源 链表中的入口节点 2.题目描述 给定一个链表&#xff0c;返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环&#xff0c;则返回 null…

08-HTML-样式和语意标签

1、<style> 标签用于为 HTML 文档定义样式信息。type 属性是必需的&#xff0c;定义 style 元素的内容。唯一可能的值是 "text/css"。style 元素位于 head 部分中。 2、<div> 可定义文档中的分区或节&#xff08;division/section&#xff09;。<div&…

Unity Audio -- (4)为声音添加特殊效果

本节我们使用声音混响区域&#xff08;audio reverb zone&#xff09;实现一些特殊效果。 什么是混响区域&#xff08;audio reverb zone&#xff09; 不同障碍物对声波的反射和吸收能力不同&#xff0c;坚硬平整表面反射声波能力强&#xff0c;松软多孔的表面吸收声波能力强。…

yolov5环境搭建(Anaconda-py3.9、PyTorch-CPU、yolov5-4.0、PyCharm)

1.环境准备 Windows 10Anaconda&#xff08;基于Python3.9&#xff09;&#xff0c;已配置好环境变量yolov5相关的代码、权重文件等&#xff0c;已经打包整理好&#xff0c;可以通过百度网盘绿色下载。链接: https://pan.baidu.com/s/1okVkfpqjI5wD6PigK-AH0w?pwdyscw 提取码…

RabbitMQ发布/订阅(交换机)

目录 RabbitMQ发布/订阅(交换机)介绍Fanout&#xff08;广播&#xff09;声明队列和交换机publisher 消息发送consumer消息接收 Direct&#xff08;定向&#xff09;consumer消息接收,基于注解声明队列和交换机publisher 消息发送总结 Topic&#xff08;通配符&#xff09;publ…

【腾讯云Finops Crane集训营】利用云原生成本优化项目实现降本增效泰酷辣~

Crane 是一个基于 FinOps 的云资源分析与成本优化平台。在保证客户应用运行质量的前提下实现极致的降本。 文章目录 一、 前言&#x1f350;二、 Crane开源项目简介&#x1f34e;2.1. Crane整体框架&#x1f352;2.2. Crane主要功能&#x1f345; 三、Crane实验前期准备&#x…

Cesium入门之二:引用Cesium并创建第一个三维地球

这一节我们来引入Cesium并创建第一个三维地图程序 Cesium的引入 1、新建一个文件夹&#xff0c;命名为first_cesium,在该文件夹下新建一个Build文件夹&#xff0c;将上一节我们下载的Cesium文件夹下Build文件夹---->Cesium文件夹下的文件全部拷贝到first_cesium---->Bu…

关于阿里云的图像搜索的创建和使用

大家好哇&#xff0c;我又来了&#xff0c;这次我们来聊下关于阿里云的图像搜索功能的创建和使用。 https://free.aliyun.com/?crowdpersonal 1、我们可以通过上面的链接进入到阿里云云产品免费试用页面&#xff0c;这里主要是阿里云为新手用户提供的免费体验的权益&#xff…

Cesium入门之一:Cesium本地运行

Cesium简介 Cesium是一个开源的、面向三维地球和地图的JavaScript库&#xff0c;它是基于Apache2.0许可的开源程序&#xff0c;可以免费的用于商业用途&#xff1b; Cesium下载 Cesium的官网地址是&#xff1a;https://cesium.com/platform/cesiumjs/&#xff0c;由于Cesium…

ChatGPT 提示语——AI提示词玩家,提示词就是和AI沟通语言的桥梁!

前言&#xff1a; 众所周知&#xff0c;在AI的世界里&#xff0c;提示词就是和AI沟通语言的桥梁&#xff0c;提示关键词常用于AI对话及AI绘画等相关场景&#xff0c;通过准确的使用关键词&#xff0c;你就能更好的让AI辅助自己的工作&#xff0c;其中的成分重要性不言而喻&…

MySQL---基本操作DQL(上)(基本查询语法,算术运算符,比较运算符,逻辑运算符,位运算符)

1. 基本查询语法 select [all|distinct] <目标列的表达式1> [别名], <目标列的表达式2> [别名]... from <表名或视图名> [别名],<表名或视图名> [别名]... [where<条件表达式>] [group by <列名> [having <条件表达式>]] [o…

JAVA学习日记 (放假了,哈哈)

每日一题 1016. 子串能表示从 1 到 N 数字的二进制串 难度中等122收藏分享切换为英文接收动态反馈 给定一个二进制字符串 s 和一个正整数 n&#xff0c;如果对于 [1, n] 范围内的每个整数&#xff0c;其二进制表示都是 s 的 子字符串 &#xff0c;就返回 true&#xff0c;否…

时间轮的golang实践浅析

引言 下列代码模仿一段RPC请求的执行过程&#xff0c;执行后会有哪些问题&#xff1a; RPC代码示例答案&#xff1a;因为超时控制后未阻断后续请求&#xff0c;导致并发读写产生Panic思考&#xff1a;客户端发起 HTTP 请求后&#xff0c;如果在指定时间内没有收到服务器的响应…

软件开发安全

软件开发安全 软件安全开发生命周期软件生命周期模型软件生命周期模型-瀑布模型软件生命周期模型-迭代模型软件生命周期模型-增量模型软件生命周期模型-快速原型模型软件生命周期模型-螺旋模型软件生命周期模型-净室模型软件安全重要性–软件危机 软件安全问题产生-内因软件安全…