1.16 LeetCode总结(基本算法)动态规划2

news2024/11/15 13:31:47

70. 爬楼梯

在这里插入图片描述
首先想到的是递归:

// 递归
int climbStairs(int n) {

	if (n == 1) {
		return 1;
	} else if (n == 2) {
		return 2;
	}

	return climbStairs(n - 1) + climbStairs(n - 2);
}

在这里插入图片描述
我们先来看看这个递归的时间复杂度吧:

递归时间复杂度 = 解决一个子问题时间*子问题个数
一个子问题时间 = f(n-1)+ f(n-2),也就是一个加法的操作,所以复杂度是 O(1);
问题个数 = 递归树节点的总数,递归树的总节点 = 2n-1,所以是复杂度O(2n)。
因此,青蛙跳阶,递归解法的时间复杂度 = O(1) * O(2^n) = O(2^n),就是指数级别的,爆炸增长的,如果n比较大的话,超时很正常的了。

回过头来,你仔细观察这颗递归树,你会发现存在大量重复计算,比如 f(8) 被计算了两次,f(7) 被重复计算了3次…所以这个递归算法低效的原因,就是存在大量的重复计算!

既然存在大量重复计算,那么我们可以先把计算好的答案存下来,即造一个备忘录,等到下次需要的话,先去备忘录查一下,如果有,就直接取就好了,备忘录没有才开始计算,那就可以省去重新重复计算的耗时啦!这就是带备忘录的解法。

自底向上的动态规划
动态规划跟带备忘录的递归解法基本思想是一致的,都是减少重复计算,时间复杂度也都是差不多。但是呢:

带备忘录的递归,是从f(10)往f(1)方向延伸求解的,所以也称为自顶向下的解法。
动态规划从较小问题的解,由交叠性质,逐步决策出较大问题的解,它是从f(1)往f(10)方向,往上推求解,所以称为自底向上的解法。
动态规划有几个典型特征,最优子结构、状态转移方程、边界、重叠子问题。在青蛙跳阶问题中:

f(n-1) 和 f(n-2) 称为 f(n) 的最优子结构
f(n) = f(n-1) + f(n-2) 就称为状态转移方程
f(1) = 1, f(2) = 2 就是边界啦
比如f(10)= f(9)+f(8), f(9) = f(8) + f(7) , f(8)就是重叠子问题。
我们来看下自底向上的解法,从 f(1) 往 f(10) 方向,想想是不是直接一个for循环就可以解决啦,如下:
在这里插入图片描述

int climbStairs(int n){
    //f(x) = f(x-1) + f(x-2) 
    if (n <= 1){ // 第0阶和第1阶只有一种方法
        return 1;
    }
    int way;
    int memo[2] = {1,1};
    for (int i = 2; i <= n; ++i) {
        // 上楼梯->从第2阶楼梯开始
        way = memo[0] + memo[1];
        memo[0] = memo[1];
        memo[1] = way;
    }
    
    return way;
}

动态规划的解题思路
动态规划的核心思想就是拆分子问题,记住过往,减少重复计算。 并且动态规划一般都是自底向上的,因此到这里,基于青蛙跳阶问题,我总结了一下我做动态规划的思路:

  1. 穷举分析
    当台阶数是1的时候,有一种跳法,f(1) = 1
    当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2;
    当台阶是3级时,想跳到第3级台阶,要么是先跳到第2级,然后再跳1级台阶上去,要么是先跳到第 1级,然后一次迈 2 级台阶上去。所以f(3) = f(2) + f(1) = 3
    当台阶是4级时,想跳到第3级台阶,要么是先跳到第3级,然后再跳1级台阶上去,要么是先跳到第 2级,然后一次迈 2 级台阶上去。所以f(4) = f(3) + f(2) = 5
    当台阶是5级时…
  1. 确定边界
    通过穷举分析,我们发现,当台阶数是1的时候或者2的时候,可以明确知道青蛙跳法。f(1) =1,f(2) = 2,当台阶n>=3时,已经呈现出规律f(3) = f(2) + f(1) =3,因此f(1) =1,f(2) = 2就是青蛙跳阶的边界。
  1. 找出规律,确定最优子结构
    n>=3时,已经呈现出规律 f(n) = f(n-1) + f(n-2) ,因此,f(n-1)和f(n-2) 称为 f(n) 的最优子结构。什么是最优子结构?有这么一个解释: 一道动态规划问题,其实就是一个递推问题。假设当前决策结果是f(n),则最优子结构就是要让 f(n-k) 最优,最优子结构性质就是能让转移到n的状态是最优的,并且与后面的决策没有关系,即让后面的决策安心地使用前面的局部最优解的一种性质
  1. 写出状态转移方程
    通过前面3步,穷举分析,确定边界,最优子结构,我们就可以得出状态转移方程啦
  1. 代码实现
    我们实现代码的时候,一般注意从底往上遍历,然后关注下边界情况,空间复杂度,也就差不多啦。动态规划有个框架的,大家实现的时候,可以考虑适当参考一下:
dp[0][0][...] = 边界值
for (状态1 :所有状态1的值) {
    for (状态2 :所有状态2的值) {
        for (...) {
          // 状态转移方程
          dp[状态1][状态2][...] = 求最值
        }
    }
}

118. 杨辉三角

在这里插入图片描述

int **generate(int numRows, int *returnSize, int **returnColumnSizes)
{
	int **res = (int **)malloc(sizeof(int *) * numRows);;
	*returnSize = numRows; // 行个数
	*returnColumnSizes = (int *)malloc(sizeof(int) * numRows); // 一维数组,每个元素代表了当前排有多少个有效的列
	printf("int *%d\n", sizeof(int *));
	printf("int %d\n",  sizeof(int));

	for (int i = 0; i < numRows; ++i) {
		res[i] = (int *)malloc(sizeof(int) * (i + 1));
		(*returnColumnSizes)[i] = i + 1; // 列元素个数
		res[i][0] = res[i][i] = 1;
		for (int j = 1; j < i; ++j) {
			res[i][j] = res[i - 1][j - 1] + res[i - 1][j];
		}
	}

	return res;
}

在LeetCode里 Sizeof(int *) 和 Sizeof(int)的大小时不一样的,注意:
https://img-blog.csdnimg.cn/311a735f68f14e01969e9f3bc327837e.png)


C 动态规划举例

在这里插入图片描述
手法1. 首先容易想到的是使用递归来求解,但递归的效率很低

// 递归 
int climbStairs(int n) {
    if (n <= 2) {
        return n;
	}

    return climbStairs(n - 1) + climbStairs(n - 2);
}

其实记忆化搜索就是在递归的条件上,为减少递归次数而产生的
比如下述代码中对于 mem[n] !=0 直接return memo[n].
我们总是习惯自顶向下思考问题,而不容易自底向上思考问题

手法2:记忆化搜索 – 自顶向下

// 记忆化搜索 -- 自顶往下
int memo[64] = { 0 };
int climbStairs(int n) {
    if (n <= 2) {
        return n;
	}
	// 如果满足条件则直接返回记忆数组里的值,减少递归次数
	if (n < 64 && memo[n] != 0) {
		return memo[n];
	}
    // 不满足条件才进行递归 O(n)
	memo[n] = climbStairs(n-1) + climbStairs(n-2);
	
	return memo[n];
}

手法3:动态规划 – 自底往上

// 动态规划 -- 自底往上
int climbStairs(int n) {
    if (n <= 2) {
        return n;
	}
    int a1 = 1;
    int a2 = 2;
    int memo = 0;
	// 自下而上的进行计算,动态规划
    for (int i = 3; i <= n; i++) {
        memo = a1 + a2;
        a1  = a2;
        a2  = memo;
    }
    return memo;
}

动态规划,将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案;
下面这个图非常清晰地说明了动态规划的引入
在这里插入图片描述


D 0-1背包问题

– 动态规划中可以解决的一类最为经典的问题 – 01背包问题
在这里插入图片描述
状态转移方程:
状态转移

调试程序可以采用如下图片的数据,利于理解背包算法:
建立一个 3*6 二维数组,第0行只考虑第0个物品;第一行考虑 a[1][2]的weight为2,既可以放在id0的物品,也可以放下id1的物品;但两者相比,id1的物品要大一些,我们考虑放id1的物品。

在这里插入图片描述
如图,在放置a[1][2]这个元素时考虑:如果不放 ID1 的物品,那么背包价值为6,如果考虑放 ID1 的物品,需要回到a[0][0]的价值,加上放 ID1 物品的价值和为10,两者比较(10 > 6),放的价值大,所以考虑放 ID1的物品。
继续布满这个图,则得到下图:
在这里插入图片描述
如图,在放置a[2][4]这个元素时考虑:如果不放 ID2 的物品,那么背包价值为16,如果考虑放 ID2 的物品,需要回到a[1][1]的价值 6 ,加上放 ID2 物品的价值和为18,两者比较(18 > 16),放的价值大,所以考虑放 ID2的物品。

如下代码,就是建立上述图片里的二维数组的值(先求解了第0行数组和第1行往后的逐列逐行数组)
在这里插入图片描述

其实我们做0-1背包问题时,就是自底向上地完善这个 3*6 的二维数组,而处理的思路正好就是 动态规划.

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

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

相关文章

剖析 SPI 在 Spring 中的应用

一、概述 SPI&#xff08;Service Provider Interface&#xff09;&#xff0c;是Java内置的一种服务提供发现机制&#xff0c;可以用来提高框架的扩展性&#xff0c;主要用于框架的开发中&#xff0c;比如Dubbo&#xff0c;不同框架中实现略有差异&#xff0c;但核心机制相同…

python+playwright 学习-88 禁止加载图片等资源

前言 对于爬虫的小伙伴来说,有时候只需抓取页面的文本,不用加载图片,可以加快操作页面速度,那么我们可以设置禁止加载图片等资源。 禁止图片加载 根据url地址的后缀,图片资源后缀一般是png,jpg,jpeg,gif等格式。 from playwright.sync_api import sync_playwrightwith…

房贷还款(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;double m, r 0.01;float d 300000;float p 6000;//运算还款所需月份&#xff1b;m log10…

2024年广东省网络系统管理样题第2套网络搭建部分

2024年广东省网络系统管理样题第2套网络搭建部分 网络系统管理赛项 模块A&#xff1a;网络构建 极安云科专注职业教育技能培训4年&#xff0c;包含信息安全管理与评估、网络系统管理、网络搭建等多个赛项及各大CTF模块培训学习服务。本团队基于赛项知识点&#xff0c;提供完整…

[C++][算法基础]图中点的层次(树图BFS)

给定一个 n 个点 m 条边的有向图&#xff0c;图中可能存在重边和自环。 所有边的长度都是 1&#xff0c;点的编号为 1∼n。 请你求出 1 号点到 n 号点的最短距离&#xff0c;如果从 1 号点无法走到 n 号点&#xff0c;输出 −1。 输入格式 第一行包含两个整数 n 和 m。 接…

社交媒体数据恢复:Whatsapp

WhatsApp数据恢复指南&#xff1a;找回丢失的聊天记录和好友 随着科技的发展&#xff0c;人们越来越依赖智能手机上的应用程序来沟通交流。作为全球最受欢迎的即时通讯软件之一&#xff0c;WhatsApp在人们的日常生活中扮演着至关重要的角色。然而&#xff0c;在使用过程中&…

七月审稿之提升模型效果的三大要素:prompt、数据质量、训练策略(含Reviewer2和PeerRead)​

前言 我带队的整个大模型项目团队超过40人了&#xff0c;分六个项目组&#xff0c;每个项目组都是全职带兼职&#xff0c;且都会每周确定任务/目标/计划&#xff0c;然后各项目组各自做任务拆解&#xff0c;有时同组内任务多时 则2-4人一组 方便并行和讨论&#xff0c;每周文档…

【Linux网络编程】UDP协议

UDP协议 1.再谈端口号端口号划分认识知名端口号(Well-Know Port Number)两个问题netstatpidof 2.UDP协议2.1UDP的特点2.2面向数据报2.3UDP的缓冲区2.4UDP使用注意事项2.5基于UDP的应用层协议 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&#xff01; 1.再谈端口号 端口…

第十五届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组

试题 C: 好数 时间限制 : 1.0s 内存限制: 256.0MB 本题总分&#xff1a;10 分 【问题描述】 一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位 &#xff09;上 的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位 &…

(三)C++自制植物大战僵尸游戏项目结构说明

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、项目结构 打开项目后&#xff0c;在解决方案管理器中有五个项目&#xff0c;分别是libbox2d、libcocos2d、librecast、libSpine、PlantsVsZombies五个项目&#xff0c;除PlantsVsZombies外&#xff0c;其他四个…

计算机网络 Cisco虚拟局域网划分

一、实验内容 1、分别把交换机命名为SWA、SWB 2、划分虚拟局域网 valn &#xff0c;并将端口静态划分到 vlan 中 划分vlan 方法一&#xff1a;在全局模式下划分vlan&#xff0c;在SWA交换机上创建三个vlan&#xff0c;分别为vlan2&#xff0c;vlan3&#xff0c;vlan4。 方…

第十五篇【传奇开心果系列】Python自动化办公库技术点案例示例:深度解读Python 自动化处理图像在各行各业的应用场景

传奇开心果博文系列 系列博文目录Python自动化办公库技术点案例示例系列 博文目录前言一、行业应用场景介绍二、 **计算机视觉研究与开发示例代码**三、人工智能与机器学习示例代码四、医疗健康领域示例代码五、制造业与质量控制示例代码六、农业与环境科学示例代码七、电子商务…

C语言单链表详解

链表和顺序表的区别 顺序表的底层存储空间是连续的&#xff0c;链表的底层存储空间是不连续的&#xff0c;链表的每个节点需要额外的指针来指向下一个节点&#xff0c;占用更多的存储空间。 顺序表的随机访问性能好&#xff0c;时间复杂度为O(1)&#xff0c;链表的随机访问性能…

利用Sentinel解决雪崩问题(一)流量控制

1、解决雪崩问题的常见方式有四种: 超时处理:设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&#xff0c;不会无休止等待;舱壁模式:限定每个业务能使用的线程数&#xff0c;避免耗尽整个tomcat的资源&#xff0c;因此也叫线程隔离;熔断降级:由断路器统计业务…

【备战测开】—— 编程语言Python(二)

续上上篇的讲解&#xff1a;【备战测开】—— 编程语言Python&#xff08;一&#xff09; 6 面向对象编程 所谓的面向对象其实就是把属性和方法封装起来&#xff0c;以供重复调用 6.1 类和对象 参考博客&#xff1a;python类和对象最全详解&#xff08;持续修订中&#xff…

网络篇06 | 应用层 自定义协议

网络篇06 | 应用层 自定义协议 01 固定协议设计&#xff08;简化版&#xff09;1&#xff09;总体设计2&#xff09;值设计 02 可变协议设计&#xff08;进阶版&#xff09;1&#xff09;固定头&#xff08;Fixed Header&#xff09;2&#xff09;可变头&#xff08;Variable H…

SpringBoot新增菜品模块开发(事务管理+批量插入+主键回填)

需求分析与设计 一&#xff1a;产品原型 后台系统中可以管理菜品信息&#xff0c;通过 新增功能来添加一个新的菜品&#xff0c;在添加菜品时需要选择当前菜品所属的菜品分类&#xff0c;并且需要上传菜品图片。 新增菜品原型&#xff1a; 当填写完表单信息, 点击"保存…

【御控物联】物联网平台设备接入-JSON数据格式转化(场景案例四)

文章目录 一、背景二、解决方案三、在线转换工具四、技术资料 一、背景 物联网平台是一种实现设备接入、设备监控、设备管理、数据存储、消息多源转发和数据分析等能力的一体化平台。南向支持连接海量异构&#xff08;协议多样&#xff09;设备&#xff0c;实现设备数据云端存…

绝地求生:杜卡迪来了,这些摩托车技巧不学一下吗?

摩托车在远古版本和现在完全不一样&#xff0c;虽然容易翻车造就了一批玩家“摩托杀手”的外号&#xff0c;但是速度可比今天快多了。 后来在蓝洞的削弱了其加速度&#xff0c;虽然资料上写着最高时速155km/h&#xff0c;但是平时游戏中一般只能拉到110~120km/h。这里写一点摩托…

Java GUI制作双人对打游戏(上)

文章目录 前言什么是Java GUI一、打开IDEA 新建一个Maven项目(后续可以打包、引入相关依赖也很容易)二、引入依赖三.绘制UI界面四.绘制JPanel面板总结 前言 什么是Java GUI Java UI&#xff0c;即Java用户界面&#xff0c;是指使用Java编程语言创建的图形用户界面&#xff08…