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


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 的二维数组,而处理的思路正好就是 动态规划.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【翻译】再见, Clean Code!

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 【翻译】再见, Clean Code!正文那是一个深夜次日早晨这只是一个阶段 【翻译】再见…

【植物大战僵尸融合机器学习】+源码

上期回顾&#xff1a; 今天给大家推荐一个Gtihub开源项目&#xff1a;PythonPlantsVsZombies&#xff0c;翻译成中就是植物大战僵尸。 《植物大战僵尸》是一款极富策略性的小游戏。可怕的僵尸即将入侵&#xff0c;每种僵尸都有不同的特点&#xff0c;例如铁桶僵尸拥有极强的抗…

【设计模式学习】单例模式和工厂模式

꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转…

Java-博客系统(前后端交互)

目录 前言 博客系统基本情况 1 创建项目&#xff0c;引入依赖 2 数据库设计 2.1 分析 2.2 建库建表 3 封装数据库 3.1 在java目录下创建DBUtil类&#xff0c;通过这个类对数据库进行封装 3.2 在java目录下创建实体类&#xff08;博客类Blog&#xff09; 3.2 在java目录下创建…

vwmare+Ubuntu20.04安装超级保姆级完整教程

强烈建议先完整的看完一遍教程在进行安装以免出现问题&#xff01;&#xff01;&#xff01; 如果遇到error&#xff1a;建议复制error后面的信息然后到浏览器搜索&#xff0c;查找解决方案&#xff0c;其次在进行某个不确定的操作时&#xff0c;建议先保存快照&#xff0c;这样…

uboot操作指令1

文章目录 前言一、信息查询命令1.bdinfo用于查看板子的信息2.printenv 打印环境变量3.version查看uboot版本 二、环境变量操作命令1.setenv修改环境变量2.setenv新建环境变量3.setenv删除环境变量 三、内存操作命令1.md 命令2.nm命令3.mm命令4.mw命令 四、网络操作命令1.ping命…

Zookeeper与kafka

目录 一、zookeeper 1.1.zookeeper概述 1.2.Zookeeper 工作机制 1.3. Zookeeper 特点 1.4.Zookeeper 数据结构 1.5.Zookeeper 应用场景 1.6.Zookeeper 选举机制 第一次启动选举机制 非第一次启动选举机制 选举Leader规则&#xff1a; 1.7.部署 Zookeeper 集群 1.7.…

AI人工智能讲师大模型培训讲师叶梓 大语言模型(LLM)在科学文献摘要领域的应用

大语言模型&#xff08;LLM&#xff09;在科学文献摘要领域的应用是一个前沿且迅速发展的技术趋势。通过结合GitHub上yobibyte的Compressor项目&#xff0c;我们可以深入探讨这一技术方案的潜力和实现方式。 技术背景 随着科学研究的快速发展&#xff0c;每天都有大量的科学文…

matlab学习(三)(4.9-4.15)

一、空域里LSB算法的原理 1.原理&#xff1a; LSB算法通过替换图像像素的最低位来嵌入信息。这些被替换的LSB序列可以是需要加入的水印信息、水印的数字摘要或者由水印生成的伪随机序列。 2.实现步骤&#xff1a; &#xff08;1&#xff09;将图像文件中的所有像素点以RGB形…

服务器数据恢复—ext3文件系统下raid5数据恢复案例

服务器数据恢复环境&故障情况&#xff1a; 某企业光纤存储上有一组由16块硬盘组建的raid5阵列。管理员发现该光纤存储上的卷无法挂载&#xff0c;经过检查发现raid5阵列中有2块硬盘离线&#xff0c;于是联系我们数据恢复中心要求数据恢复工程师到现场恢复服务器存储上的数据…

【可能是全网最丝滑的LangChain教程】七、LCEL表达式语言

系列文章地址 【可能是全网最丝滑的LangChain教程】一、LangChain介绍-CSDN博客 【可能是全网最丝滑的LangChain教程】二、LangChain安装-CSDN博客 【可能是全网最丝滑的LangChain教程】三、快速入门LLM Chain-CSDN博客 【可能是全网最丝滑的LangChain教程】四、快速入门Re…

在js中计算两个时间段重叠的时长问题

文章目录 前言一、过程分析二、实现代码(js)总结 前言 最近遇到一个需求&#xff0c;就是在js中计算两段时间的重叠时长问题&#xff0c;这里记录一下。 一、过程分析 两段时间的重叠问题&#xff0c;一般有3中情况 两段时间完全无重叠&#xff0c;也就是无任何交集两段时间…

软考中级--网络工程师-计算机基础与理论第二节无线基础知识

IEEE802.11 规定了多种 WLAN 通信标准&#xff0c;其中&#xff08; &#xff09;与其他标准采用的频段不同&#xff0c;因而不能兼容。 A IEEE802.11a B IEEE802.11b C IEEE802.11g D IEEE802.11n 试题答案 正确答案&#xff1a; A 答案解析 IEEE 802.11a规定采用5GHz的 ISM频…

007Node.js安装自启动工具supervisor运行js文件

在vscode中&#xff0c;某些运行中的程序修改xx.js文件后&#xff0c;通过CtrlC终止再重新运行。supervisor是自启动工具&#xff0c;会不停的查看你的文件&#xff0c;一旦发现有修改&#xff0c;就立马重新载入运行。 我们可以通过安装supervisor代替node命令运行xx.js。终端…

环境变量与进程优先级

目录 进程的优先级 什么是优先级 为什么要有优先级 linux的优先级特点和查看方式 其他概念 环境变量 命令行参数 环境变量 查看环境变量方法 修改PATH 其他环境变量 进程的优先级 什么是优先级 优先级&#xff1a;指定进程获得某种资源的先后顺序。&#xff08;优先级…

Python数据分析案例40——电商直播间成交金额预测

承接上一篇案例电商直播间提取的特征&#xff0c;进而做一篇机器学习的案例&#xff0c;来预测直播间的成交金额。 Python数据分析案例39——电商直播间评论可视化分析&#xff08;LDA&#xff09; 1. 引言 1.1 直播电商与传统电商的比较 直播电商作为一种新兴的电子商务模式…

c语言中<string.h>的strstr与strtok函数

c语言中string.h的strstr与strtok函数 代码运行结果 代码 #include <stdio.h> #include <string.h>///1.在字符串str1里面,查找第一次出现str2的位置 //char * strstr(const char * str1,const char * str2)///2.sep为分割符,根据分割符来对str进行分割 //char * …

【WEEK7】 【DAY5】JDBC—PreparedStatement Object【English Version】

2024.4.12 Friday Following 【WEEK7】 【DAY4】JDBC—Statement Object【English Version】 Contents 10.3.PreparedStatement Object10.3.1.PreparedStatement can prevent SQL injection, more efficient than statement10.3.2. Insertion10.3.3. Deletion10.3.4. Update10.…

Windows版PHP7.4.9解压直用(免安装-绿色-项目打包直接使用)

安装版和解压版 区别 安装版: 安装方便&#xff0c;下一步------下一步就OK了&#xff0c;但重装系统更换环境又要重新来一遍&#xff0c;会特别麻烦解压版&#xff08;推荐&#xff09;&#xff1a; 这种方式&#xff08;项目打包特别方便&#xff09;能更深了解mysql的配置&…

C 408—《数据结构》易错考点200题(含解析)

目录 Δ前言 一、绪论 1.1 数据结构的基本概念 : 1.2 算法和算法评价 : 二、线性表 2.2 线性表的顺序表示 : 2.3 线性表的链式表示 : 三、栈、队列和数组 3.1 栈 3.2 队列 3.3 栈和队列的应用 3.4 数组和特殊矩阵 四、串 4.2 串的模式匹配 五、树与二叉树 5.1 树的基…