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

前言

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

动态规划(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 代码实现,例子也很详细。

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

相关推荐
brief of gali4 分钟前
记录一个奇怪的前端布局现象
前端
დ旧言~23 分钟前
【高阶数据结构】图论
算法·深度优先·广度优先·宽度优先·推荐算法
张彦峰ZYF28 分钟前
投资策略规划最优决策分析
分布式·算法·金融
The_Ticker44 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Json_181790144801 小时前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
大数据编程之光1 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
风尚云网1 小时前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
木子02041 小时前
前端VUE项目启动方式
前端·javascript·vue.js