423,动态规划和递归解最小路径和

news/2024/11/29 10:36:59/

想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
在这里插入图片描述

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

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

示例:

输入:

[

[1,3,1],

[1,5,1],

[4,2,1]

]


输出: 7

解释: 因为路径 1→3→1→1→1 的总和最小。


动态规划求解

这题求的是从左上角到右下角,路径上的数字和最小,并且每次只能向下或向右移动。所以上面很容易想到动态规划求解。我们可以使用一个二维数组dp,dp[i][j]表示的是从左上角到坐标(i,j)的最小路径和。那么走到坐标(i,j)的位置只有这两种可能,要么从上面(i-1,j)走下来,要么从左边(i,j-1)走过来,我们要选择路径和最小的再加上当前坐标的值就是到坐标(i,j)的最小路径。


所以递推公式就是

dp[i][j]=min(dp[i-1][j]+dp[i][j-1])+grid[i][j];


有了递推公式再来看一下边界条件,当在第一行的时候,因为不能从上面走下来,所以当前值就是前面的累加。同理第一列也一样,因为他不能从左边走过来,所以当前值只能是上面的累加。

在这里插入图片描述

比如上面图中,如果我们走到中间这一步的话,我们可以从上面1→3→5走过来,也可以从左边1→1→5,我们取最小的即可。我们来看下代码

public int minPathSum(int[][] grid) {int m = grid.length, n = grid[0].length;int[][] dp = new int[m][n];dp[0][0] = grid[0][0];//第一列只能从上面走下来for (int i = 1; i < m; i++) {dp[i][0] = dp[i - 1][0] + grid[i][0];}//第一行只能从左边走过来for (int i = 1; i < n; i++) {dp[0][i] = dp[0][i - 1] + grid[0][i];}for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {//递推公式,取从上面走下来和从左边走过来的最小值+当前坐标的值dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}return dp[m - 1][n - 1];
}

我们看到二维数组dp和二维数组grid的长和宽都是一样的,没必要再申请一个dp数组,完全可以使用grid,来看下代码

public int minPathSum(int[][] grid) {int m = grid.length, n = grid[0].length;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (i == 0 && j == 0)continue;if (i == 0) {//第一行只能从左边走过来grid[i][j] += grid[i][j - 1];} else if (j == 0) {//第一列只能从上面走下来grid[i][j] += grid[i - 1][j];} else {//递推公式,取从上面走下来和从左边走过来的最小值+当前坐标的值grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]);}}}return grid[m - 1][n - 1];
}

递归求解

我们还可以把上面的动态规划改为递归,定义一个函数

minPathSum(int[][] grid, int i, int j)表示从左上角到坐标(i,j)的最短路径和,那么同样道理,要走到坐标(i,j)只能从上面下来或者左边过来。所以代码轮廓我们大致能写出来

public int minPathSum(int[][] grid, int i, int j) {if (边界条件的判断) {return}//一些逻辑处理//取从上面走下来和从左边走过来的最小值+当前坐标的值return grid[i][j] + Math.min(minPathSum(grid, i - 1, j), minPathSum(grid, i, j - 1));
}

下面再来看下完整代码

public int minPathSum(int[][] grid) {return minPathSum(grid, grid.length - 1, grid[0].length - 1);
}public int minPathSum(int[][] grid, int i, int j) {if (i == 0 && j == 0)return grid[i][j];//第一行只能从左边走过来if (i == 0)return grid[i][j] + minPathSum(grid, i, j - 1);//第一列只能从上面走下来if (j == 0)return grid[i][j] + minPathSum(grid, i - 1, j);//取从上面走下来和从左边走过来的最小值+当前坐标的值return grid[i][j] + Math.min(minPathSum(grid, i - 1, j), minPathSum(grid, i, j - 1));
}

因为这里面的递归会导致大量的重复计算,所以还是老方法,就是把计算过的值存储到一个map中,下次计算的时候先看map中是否有,如果有就直接从map中取,如果没有再计算,计算之后再把结果放到map中,来看下代码

public int minPathSum(int[][] grid) {return minPathSum(grid, grid.length - 1, grid[0].length - 1, new HashMap<String, Integer>());
}public int minPathSum(int[][] grid, int i, int j, Map<String, Integer> map) {if (i == 0 && j == 0)return grid[i][j];String key = i + "*" + j;if (map.containsKey(key))return map.get(key);int res = 0;//第一行只能从左边走过来if (i == 0)res = grid[i][j] + minPathSum(grid, i, j - 1, map);//第一列只能从上面走下来else if (j == 0)res = grid[i][j] + minPathSum(grid, i - 1, j, map);//取从上面走下来和从左边走过来的最小值+当前坐标的值elseres = grid[i][j] + Math.min(minPathSum(grid, i - 1, j, map), minPathSum(grid, i, j - 1, map));map.put(key, res);return res;
}

总结

这题使用动态规划应该说是最容易理解的,也可以参照前面的409,动态规划求不同路径和411,动态规划和递归求不同路径 II,只不过递推公式会有点差别。


在这里插入图片描述


http://www.ppmy.cn/news/841642.html

相关文章

LLM - Baichuan7B Tokenizer 生成训练数据

目录 一.引言 二.Tokenizer 原始数据 1.原始数据样例 2.加载并 Token 原始数据 2.1 参数准备 2.2 单条样本处理逻辑 2.3 批量处理逻辑 2.4 主函数与完整代码 三.shell 执行 四.总结 一.引言 前面提到了自己在微调 Baichuan7B Lora 的过程中遇到了一些问题&#xff0c…

刷题记录01

题目一. 这道题要先解释一下什么是非递增,非递增就是a[i] >a[i1],递增则是相反. 非递减就是a[i]>a[i1],递减就是相反 大方向思路是: 遍历数组判断相邻元素的顺序关系统计排序子序列数量 具体思路: 本题依次比较整个数组a[i1]>a[i] &#xff0c;则进入非递增序列判…

爬虫之Scrapy框架爬取彼岸壁纸案例分享

爬虫之Scrapy框架爬取彼岸壁纸案例分享 前段时间在网上看到有人爬取了彼岸壁纸的案例&#xff0c;由于爬取的图片较多&#xff0c;爬取速度感觉不快&#xff0c;所以就自己写了个Scrapy框架&#xff0c;个人觉得爬取速度快多了。 代码如下。 文章目录 爬虫之Scrapy框架爬取彼岸…

全套英雄联盟系列壁纸,确定不来了解一下?

前言 我曾踏足山巅,也曾跌落低谷,二者都让我受益良多 最近喜欢在文章前面加入联盟的壁纸,一是为了填充内容,不显得内容干燥,二是这些壁纸看起来确实很帅哈哈 于是花了点时间找了些LOL的壁纸网站,最终锁定了https://lolskin.cn/ 英雄联盟皮肤站,看了下这个站还是很不错的…

python随机爬取wallhaven壁纸url(获取随机图片url)

01 代码清单 class get_random_wallhaven(object):def __init__(self, url https://wallhaven.cc/random):self.init_url urldef getHTMLText(self, url):import urllib3headers {User -Agent : Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Geck…

deepin切换壁纸小工具

切换壁纸小工具(python脚本) 切换壁纸这种事,找到接口,一行代码就可以解决,本来打算用bash脚本,但是考虑到随机选取壁纸等因素,用python的os模块完成任务。 一、思路 找到切换壁纸的接口设置壁纸库(文件夹)python脚本完成功能半小时自动切换壁纸二、实现过程 1、切…

JAVA爬虫---LOL各英雄图片(含皮肤)下载

pom依赖 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifact…

利用Scrapy框架爬取LOL皮肤站高清壁纸

利用Scrapy框架爬取LOL皮肤站高清壁纸 Lan 2020-03-06 21:22 81 人阅读 0 条评论 成品打包&#xff1a;点击进入 代码&#xff1a; 爬虫文件 # -*- coding: utf-8 -*- import scrapy from practice.items import PracticeItem from urllib import parseclass LolskinSpider(s…