10|面试即正义第二期:常见的动态规划面试题串烧
简单的路径规划
算法问题分析
- 深入了解
- 翻译
- 解释
- 总结
动态规划是解决多种类型算法问题的重要方法,包括背包问题、子数组问题和子序列问题等。本文从最简单的路径规划问题入手,介绍了动态规划的基本思想和应用。通过分析重叠子问题、无后效性和最优子结构,确定了可以利用动态规划思想进行求解。文章进一步讨论了带障碍的路径规划问题,考虑了网格中存在障碍物的情况,但问题本质并未改变。接着,介绍了跳跃游戏问题,通过分析动态规划特征,给出了状态转移方程和Java、C++的实现代码。通过以上讲解,读者可以快速了解动态规划的应用和解题思路,以及如何应用动态规划解决路径规划和可行性问题。文章还提到了如何将其他类型的问题转化为求可行性类型的动态规划问题,并鼓励读者尝试解决实际的面试问题,加深对解题模板的利用和理解。最后,文章提出了一个课后思考问题,引发读者思考如何在带障碍的路径规划问题的基础上,求出从起点到终点的最大长度。整体而言,本文通过具体问题的讲解和实例代码的提供,帮助读者快速了解动态规划的应用和解题思路,以及如何应用动态规划解决路径规划和可行性问题。
《动态规划面试宝典》,新⼈⾸单¥59
全部留言(9)
- 最新
- 精选
- 宋不肥带障碍的可行性那个题目在leetcode上要求打出路径,补一个带路劲的c++代码给有需要的小伙伴 //leetcode:面试题 08.02. 迷路的机器人 class Solution { public: vector<vector<int>> pathWithObstacles(vector<vector<int>>& obstacleGrid) { // 判断边界条件 vector<vector<int>> res; int row = obstacleGrid.size(); if(!row) return res; int col = obstacleGrid[0].size(); if(!col) return res; if(obstacleGrid[0][0] == 1 || obstacleGrid[row -1][col -1] == 1) return res; // 初始化边界条件 int dp[row][col];memset(dp,0,sizeof(dp)); dp[row-1][col-1] = 1; for(int i{row-2} ; i>=0;i--) {//初始化最后一列 if(obstacleGrid[i][col-1] == 1) dp[i][col-1] = 0; else dp[i][col-1] = dp[i+1][col-1]; } for(int i{col-2};i>=0;i--) {//初始化最后一行 if(obstacleGrid[row-1][i] == 1) dp[row-1][i] = 0; else dp[row-1][i] = dp[row-1][i+1]; } //求路径 for(int i{row-2};i>=0;--i) { for(int j{col-2}; j>=0 ;--j) { if(obstacleGrid[i][j] == 1) dp[i][j] = 0; else dp[i][j] = max(dp[i+1][j],dp[i][j+1]); } } if(dp[0][0] == 0) return res; int r{0},c{0}; while(r != row-1 || c != col-1) { res.push_back({r,c}); int down{0};//内部变量不会默认初始化C++,一定要小心 if(r < row-1) down = dp[r+1][c]; int right{0}; if(c < col-1) right = dp[r][c+1]; if(down >= right) r++; else c++; } res.push_back({row-1,col-1}); return res; } }; 话说回来,感觉老师这个专利每篇质量不一啊,大部分都挺好,但背包问题那两讲,图画的有问题,备忘录,重叠子问题部分描述的有些晦涩,劝退了好多小伙伴啊,感觉把那两章重新写一哈,这个专栏的价值能翻一倍
作者回复: 没有问题,很好,有时间可以多刷刷leetcode,给自己提出更高的要求。也可以参考14|面试即正义第三期:刷题指南,熟能生巧~ 有关于重叠子问题,在13|动态规划算法设计的关键:最优子结构与状态依赖有更深入的讲解。对于图的解释,稍后会作出改进和更新。
2020-11-0334 - 我是一把火跳跃游戏题目,我尝试了一下只用一层for循环,dp[i]保存的是所能达到的最远位置,每次需要先判断一下可达的最远位置是否能够到当前位置。 def canJump(arr): dp = [0 for _ in range(len(arr))] dp[0] = arr[0] for i in range(1, len(arr)): if dp[i-1] < i: return False dp[i] = max(dp[i-1], i + arr[i]) return True
作者回复: 没有问题,赞! 这道题目动态规划本身也不是最优方案,有很多的可优化之处。
2020-10-0763 - Jonathan带障碍物的不同路径中,初始化操作除了(0,0)位置是根据数组值进行判断,其他应该是根据上一个dp值进行判断吧。比如(0,1)位置是障碍物,那么(0,2)肯定就是0。因为没办法通过(0,0)走到(0,2)
作者回复: 只要有一个格子具有障碍物后面都是0,因为无法向上走。
2021-04-1222 - 傻猫周大福为何不试试逆序遍历呢 func JumpGame(arr []int) bool { index := len(arr) - 1 for i := index - 1; i >= 0; i-- { if i+arr[i] >= index { index = i } } if index == 0 { return true } return false }
作者回复: 这个问题其实最好的方法不是递归,只是为了训练如何使用递归求解问题。能思考更好的解决方案是很好的!给你一个赞。
2020-10-112 - 每天晒白牙有障碍物的路径问题,老师的java版代码应该是有问题的,在leetcode上提交是失败的,在初始化那块有点问题,第一列只要存在障碍物,应该直接break出循环,第一行的初始化也一样 public int uniquePathsWithObstacles(int[][] obstacleGrid) { // 行数 int m = obstacleGrid.length; // 列数 int n = obstacleGrid[0].length; int[][] dp = new int[m][n]; // 初始化状态 for(int i = 0; i < m; i++) { dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : 1; // 第一列只要出现障碍物,下面的肯定是0 if(obstacleGrid[i][0] == 1) { break; } } for(int j = 0; j < n; j++) { dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : 1; // 第一行只要出现障碍物,后面的肯定是0 if(obstacleGrid[0][j] == 1) { break; } } // 状态转移方程 for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { if (obstacleGrid[i][j] == 1) { dp[i][j] = 0; } else { dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } } return dp[m-1][n-1]; }
作者回复: 是的,这里代码需要修改,0代表有障碍,如果第一行或者第一列遇到了障碍,后面的应该都是算会遇到障碍。 感谢你指出问题,正文已修正。
2021-02-121 - xuanyuan二刷,都是自己独立思考递推公式,找到感觉了,非常赞的专栏
作者回复: 恩,学习的最好方法就是自己独立思考如何解决问题。
2020-11-141 - 帽子狗第一个老数学题了, 机器人一定会走 m + n - 2 步,其中有 n - 1步往下走。 所以结果C((m+n-2), (n-1))。 不过计算组合数可能溢出,dp算是大数求组合数的防溢出方案吧。
作者回复: 其实DP也就是用更加朴素的思想来求解。当然数字一大直接计算组合数的确容易溢出。
2020-11-09 - 混混带障碍的路径问题中,初始状态,对应第一行或者第一列,出现一个障碍后,后面的路径是不是都应该为0,而不是只有障碍的地方是0?
作者回复: 如果考虑实现优化的确是这样。但是为了让初始化和后面的求解过程看起来清晰明了,所以这里在初始化就不做过多的延伸了。但是如果理解了动态规划的确可以做这种实现上的优化。
2020-10-052 - webmin//v[i][j] - i为行,j为列,值为0时表示此路不通,大于0时表示从上方或左方到达此点的长度 // 0 <= i,j < 1000 //0 <= v[i][j] < 1000 int getMaxPathLenWithBlocks(int[][] v) { int m = v.length; int n = v[0].length; int[][] dp = new int[m][n]; // 初始化状态 for (int i = 0; i < m; i ++) { dp[i][0] = v[i][0] == 0 ? 0 : i > 0 ? dp[i-1][0] + v[i][0]: v[i][0]; } for (int j = 0; j < n; j ++) { dp[0][j] = v[0][j] == 0 ? 0 : j > 0 ? dp[0][j-1] + v[0][j]: v[0][j]; } for (int i = 1; i < m; i ++) { // 状态转移过程 for (int j = 1; j < n; j ++) { if (v[i][j] == 0) { dp[i][j] = 0; } else { dp[i][j] = Math.max(dp[i - 1][j],dp[i][j - 1]) + v[i][j]; } } } return dp[m - 1][n - 1]; // 输出答案 }
作者回复: 没有问题,赞。
2020-10-05