详解动态规划(算法村第十九关青铜挑战)

不同路径

62. 不同路径 - 力扣(LeetCode)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

递归

递归的含义就是处理方法不变,但是问题的规模减少。

public int uniquePaths(int m, int n)
{//如果只剩一行或者一列,那只有一个方向,一条路径了if (m == 1 || n == 1)return 1;//往右走一步,问题规模缩小成 m * (n-1) 的网格//往下走一步,问题规模缩小成 (m-1) * n 的网格return uniquePaths(m, n - 1) + uniquePaths(m - 1, n);
}

但在此题中普通的递归解法超时,原因是存在大量重复计算。

在这里插入图片描述

例如,不管是从(0,1)还是(1,0)从来到(1,1),接下来从(1,1)到终点都会有2种走法,不必每次都重新计算。而普通的递归只能一遍又一遍地计算从(1,1)到终点有多少种走法。

利用二维数组进行记忆化搜索

在这里插入图片描述

每个格子的数字表示从起点开始到达当前位置的路径数,计算总路径时可以先查一下记录,如果有记录就直接读,没有再计算,这样就可以避免大量重复计算,这就是记忆化搜索

  • 第一行和第一列都是1。
  • 其他格子的值 = 左侧格子的值 + 上方格子格子的值。

如图中的4,由上面的1和左侧的3计算而来,15由上侧的5和左侧的10计算而来。

public int uniquePaths_2(int m, int n)
{int[][] record = new int[m][n];record[0][0] = 1;for (int row = 0; row < m; ++row)for (int col = 0; col < n; ++col){if (row > 0 && col > 0)record[row][col] = record[row - 1][col] + record[row][col - 1];else if (col > 0)	//第一行格子record[row][col] = record[row][col - 1];else if(row > 0)	//第一列格子record[row][col] = record[row - 1][col];}return record[m - 1][n - 1];
}

将二维数组优化为一维数组

第一步,用1填充一维数组。

在这里插入图片描述

第二步,从头遍历数组,除了第一个位置,位置的新值 = 前一个位置的值 + 位置的原始值 。其实,在二维数组中,位置的原始值就在位置新值的上方。

在这里插入图片描述

重复第二步

在这里插入图片描述

把三个一维数组拼接起来,发现恰好跟上面的二维数组一致:

在这里插入图片描述

所以,路径总数就是一维数组最后一个元素的值。

这种反复更新的一维数组就是滚动数组。

public int uniquePaths_3(int m, int n)
{int[] dp = new int[n];Arrays.fill(dp,1);for (int row = 1; row < m; row++)for (int col = 1; col < n; col++)dp[col] = dp[col - 1] + dp[col];return dp[n - 1];
}

总结

这个题目涵盖了dp的多个方面,比如重复子问题(递归)、记忆化搜索(将已经计算好的结果存入数组,后面用到就直接读取)、滚动数组(二维数组优化为一维数组)。

最小路径和

64. 最小路径和 - 力扣(LeetCode)

给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

**说明:**每次只能向下或者向右移动一步

public int minPathSum(int[][] grid)
{//逐行遍历,更新 grid 的格值,作为[在方向约束下,从起点到当前格的最小路经和]for (int row = 0; row < grid.length; row++)for (int col = 0; col < grid[row].length; col++){if (row == 0 && col == 0)continue;else if (row == 0)  //只能往右走grid[row][col] = grid[row][col - 1] + grid[row][col];else if (col == 0)  //只能往下走grid[row][col] = grid[row - 1][col] + grid[row][col];else                //从[往右、往下]两个方向挑路径和最小的走grid[row][col] = Math.min(grid[row][col - 1], grid[row - 1][col]) + grid[row][col];}return grid[grid.length - 1][grid[0].length - 1];
}

在这里插入图片描述

我们完全不需要建立 dp 矩阵浪费额外空间,直接遍历 grid 并修改其值即可。因为原 grid 矩阵元素中被覆盖为 dp 元素后(都处于当前遍历点的左上方),不会再被使用到。

三角形最小路径和

120. 三角形最小路径和 - 力扣(LeetCode)

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 ii + 1

示例 1:

输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:23 46 5 7
4 1 8 3
自顶向下的最小路径和为 11(即 2 + 3 + 5 + 1 = 11)。

自底向上 dp + 空间优化

public int minimumTotal(List<List<Integer>> triangle)
{int[] dp = new int[triangle.size() + 1];  //多出一格是为了dp数组能够获取triangle最底层的值// 从最底层开始 dpfor (int row = triangle.size() - 1; row >= 0; row--)for (int col = 0; col < row + 1; col++) //第 row 行有 row + 1个数dp[col] = Math.min(dp[col], dp[col + 1]) + triangle.get(row).get(col);//顶点储存着从最底层到顶点的最小路径和return dp[0];
}

理论上可以直接修改triangle的值而不用额外申请空间,但由于triangle的类型是List<List<Integer>>,修改起来很繁琐,故还是选择申请这O(n)dp空间

区分动态规划和回溯

  • 动态规划:只关心当前结果是什么,而不记录结果怎么来的,无法获得完整的路径
  • 回溯:能够获得一条乃至所有满足要求的完整路径。

动态规划题目的三种基本的类型

  1. 计数相关。例如求有多少种方式走到右下角,有多少种方式选出K个数使得…,等等。
  2. 求最大最小值,最多最少。例如最大数字和、最长上升子序列长度、最长公共子序列、最长回文序列等等。
  3. 求存在性。例如取石子游戏,先手是否必胜;能不能选出K个数使得…,等等。

解决问题的模板

  1. 确定状态和子问题。一些题目用逆向思维分析会更容易。
  2. 确定状态转移方程,也就是确定 dp 数组要如何更新状态(或者直接在原数组上改动)。
  3. 确定初始条件和边界情况。
  4. 按照顺序计算。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考-中级-系统集成2023年综合知识(四)

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 软考中级专栏回顾 专栏…

电子签名技术如何保障电子合同的法律效力?

在当今数字化浪潮中&#xff0c;电子合同和电子签名逐渐取代了传统的纸质合同和手写签名&#xff0c;成为商业活动中的新宠。尽管如此&#xff0c;许多人对于电子签名的法律效力仍存有疑问。以下是对电子合同和电子签名相关法律效力的详细解读。 首先&#xff0c;让我们澄清什么…

数据中台:数字中国战略关键技术实施

这里写目录标题 前言为何要建设数据中台数据中台建设痛点数据中台学习资料聚焦前沿&#xff0c;方法论体系更新与时俱进&#xff0c;紧跟时代热点深入6大行业&#xff0c;提炼实践精华大咖推荐&#xff0c;数字化转型必备案头书 前言 在数字中国这一国家战略的牵引下&#xff0…

TypeScript 哲学 - everyday Type

1、 2、TypeScript a structurally typed type system. 3、 type vs interface 3、literal reference 4、non-null assertion operator

【简说八股】Redisson的守护线程是怎么实现的

Redisson Redisson 是一个 Java 语言实现的 Redis SDK 客户端&#xff0c;在使用分布式锁时&#xff0c;它就采用了「自动续期」的方案来避免锁过期&#xff0c;这个守护线程我们一般也把它叫做「看门狗」线程。 Redission是一个在Java环境中使用的开源的分布式缓存和分布式锁实…

mac报错:zsh:command not found: brew

1、基本概述&#xff1f; 在使用brew安装程序的时候MAC提示&#xff1a; zsh:command not found: brew 本质就是brew没有安装&#xff0c;这个命令与linux系统中的yum命令类似。 使用的环境说明&#xff1a; 虚拟机版本&#xff1a;VMware Workstation 17 Pro mac os Ventu…

基于springboot实现粮食仓库管理系统项目【项目源码+论文说明】

基于springboot实现粮食仓库管理系统演示 摘要 粮食作为人类生活的重要物质来源&#xff0c;在粮食流通过程中对于粮食仓库的管理不容忽视&#xff0c;随着我国粮食生产能力的提升以粮食存储管理的不断革新&#xff0c;粮食产量的增加为粮食仓储管理带来了挑战也带来了机遇&am…

二叉树的深度,求第k层的节点个数,二叉树的销毁,二叉树寻找值为x的节点

文章目录 一、二叉树的深度二、二叉树的k层节点个数三、二叉树的销毁四、二叉树查找值为x的节点 一、二叉树的深度 int BTreeHeight(BTNode* root) {if (root NULL)return 0;int rightHeight BTreeHeight(root->right);int leftHeight BTreeHeight(root->left);retur…

生态系统碳循环模型CENTURY建模方法应用

CENTURY模型&#xff0c;主要基于过程的陆地生态系统生物地球化学循环模型。主要用于模拟不同土壤-植被系统间C、N、P和S的长期动态。根据土壤有机质的分解速率&#xff0c;CENTURY模型将土壤总有机碳&#xff08;TOC&#xff09;分成了三个碳库&#xff0c;即活性、慢性和惰性…

STM32(13)串口

串口的数据帧 1.空闲 2.起始位 3.数据位 4.校验位&#xff08;可有可无&#xff09; 为了验证数据传输是否出错而设立的比特位 1和4传输方式比较常见 校验规则&#xff1a; 根据1的个数&#xff0c;校验位会自己补0或1 5.停止位 例子&#xff1a; 同步通信 异步通信 波特率 …

IIS发布PHP网站字体404解决办法

最近在使用 IIS 发布 PHP 网站时&#xff0c;我遇到了一个前端问题&#xff0c;即字体库文件 404 错误。这个问题的根本原因是 IIS 未能正确识别字体文件类型&#xff0c;导致浏览器在加载页面时无法正确获取所需字体资源&#xff0c;进而触发了404错误。这样的问题会导致网站页…

基于嵌入式的车载导航定位系统设计

一、前言 1.1 项目介绍 【1】项目背景 随着汽车工业的飞速发展和智能化技术的不断突破&#xff0c;车载导航系统作为现代汽车不可或缺的一部分&#xff0c;在人们的日常生活中扮演着越来越重要的角色。它不仅能够提供精确的路线导航&#xff0c;还能提供丰富的地理信息和娱乐…