🥳前端算法面试--动态规划之最短路径-每日一练

前言

今天分享的内容是前端必问算法,没有之一--动态规划。

动态规划(Dynamic Programming, DP)是一种在数学、计算机科学和经济学领域中使用的解决复杂问题的方法。它的核心思想是将问题分解成相互依赖的子问题,然后用一个表格存储这些子问题的解,以避免重复计算。动态规划适用于具有重叠子问题和最优子结构特点的问题,通常可用于求解最优化问题。

提炼几个关键点:

  1. 重复的子问题
  2. 最优结构子问题
  3. 避免重复计算

其中,第一个点和上篇文章讲到的回溯算法一致,都是将一个大问题分解成多个重复的子问题。而后面两点就是动态规划的独有特点了。动态规划可以通过找到最优结构的子问题,从而避免重复计算

本篇文章的问题和上篇文章的问题一致,即找到方格的最短路径

假设 n*n 的方格,每个方格都有一个数字,表示这个方格的权重。现在要从(0,0)走到(n-1, n-1),有很多路径。就像下面这个九宫格,从左上角走到右下角,可以右右右下下下,也可以下下下右右右,也可以右右下下下右,有很多种走法,每种走法的权重都不一样,现在要找到权重之和最小的那条路径

问题描述摘抄自上篇文章🥳前端算法面试之找到最短路径-每日一练 - 掘金,这里还有用回溯算法解决该问题的讲解

问题分析

用回溯算法的解决思路就是找到所有的路径,但是这里还有优化的空间。

就拿上面的九宫格举例子,假设已经走到了(1,1)这个位置,那么有两种可能,一种是走(0,0)->(1,0)->(1,1),那么路径权重就是 12, 还有一种是走(0,0)->(0,1)->(1,1),这样路径权重就是 18 了。其实对于后者就没必要继续算下去了,直接使用前者的路线继续算就可以了。但对于回溯算法,每种权重还是会继续算下去,这就是回溯算法时间复杂度高的原因。

动态规划对回溯算法优化,正是从这个方向入手。走到某一格,只保留最短的权重路径,从而继续下去。直接抛弃其他的路径走法。

对于任何一格,可以往下走的选择都是要么往右,要么往下。假设现在走到了 (i,j) 格,它的上一步的路径来源也就要么来自上方(i-1,j),要么来自左方(i,j-1)。然后它只要选择这两个路径中最短权重的,加上自身的权重 weight(i,j),意思是走到了它这一格,最短路径是 weight(i,j) + min( weight(i-1,j), weight(i, j-1) )。 如果 X 不是重点的话,就相当于挑了一条最短路径继续往下走。如果 X 是重点,那么整个方格的最短路径的权重就求出来了。

到这里,思路分析得差不多了,下面看代码怎么实现的

动态规划的实现

javascript 复制代码
/**
 *
 * @param {number[][]} data
 */
const findShortPath = (data) => {
  // 初始化path数组
	const path = Array(data.length)
		.fill(0)
		.map(() => Array(data.length).fill(0));

	path[0][0] = data[0][0];

  // 初始化行
	for (let i = 1; i < data.length; i++) {
		path[0][i] = path[0][i - 1] + data[0][i];
	}

  // 初始化列
	for (let j = 1; j < data.length; j++) {
		path[j][0] = path[j - 1][0] + data[j][0];
	}

  // 计算剩下的格子
	for (let i = 1; i < data.length; i++) {
		for (let j = 1; j < data.length; j++) {
			path[i][j] = data[i][j] + Math.min(path[i - 1][j], path[i][j - 1]);
		}
	}
	// check
	console.log(path);
	console.log("the min weight is: ", path[data.length - 1][data.length - 1]);
};

代码的逻辑也是按照上面分析的来,计算每个格子的时候,值为data[i][j] + Math.min(path[i - 1][j], path[i][j - 1]),意为选取最短的路径往下走。注意⚠️,相较于回溯算法,动态规划的高明之处正在于此,只保留最短路径往下走,而不是计算所有的路径值。

在计算路径之前,先要初始化第 1 行和第 1 列的数据,方便后面的计算。

计算完成之后,函数的末尾会打印出 path,大家可以看看生成的 path 长什么样子。并且 path 最后一格的值就是我们要求的最短路径

执行代码

javascript 复制代码
const data = [
	[3, 4, 2, 1],
	[5, 2, 4, 1],
	[7, 6, 4, 3],
	[5, 9, 2, 4],
];

findShortPath(data);

输出结果:

下面测试几个简单的方格数据,方便大家判断代码的正确性:

例一

javascript 复制代码
const data = [
	[1, 2, 2],
	[1, 2, 2],
	[1, 1, 1],
];

打印结果:

例二

javascript 复制代码
const data = [
	[1, 2, 2],
	[1, 0, 2],
	[1, 0, 1],
];

打印结果:

代码正确🙆

总结

这篇文章分享了如何用动态规划的方法找到权重最短的路径,并且分析了回溯算法复杂度高的原因,从原因入手,就是动态规划提高性能的方向,即保留局部最优的路径,其他的路径可能性就不考虑。同时文中给出了 JS 代码实现,例子也很详细。

可以评论区留言哦。我每天都会分享一篇算法小练习,喜欢就点赞+关注吧

相关推荐
limingade3 小时前
手机实时提取SIM卡打电话的信令和声音-新的篇章(一、可行的方案探讨)
物联网·算法·智能手机·数据分析·信息与通信
编程零零七3 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
(⊙o⊙)~哦5 小时前
JavaScript substring() 方法
前端
无心使然云中漫步5 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
jiao000015 小时前
数据结构——队列
c语言·数据结构·算法
Bug缔造者5 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_6 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
迷迭所归处6 小时前
C++ —— 关于vector
开发语言·c++·算法
麒麟而非淇淋7 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120537 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab