欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

每天一道LeetCode-----计算从二维数组的左上角到达右下角的所有路径数及最短的那条,如果存在障碍物时又是多少

发布时间:2024/4/19 编程问答 67 豆豆
生活随笔 收集整理的这篇文章主要介绍了 每天一道LeetCode-----计算从二维数组的左上角到达右下角的所有路径数及最短的那条,如果存在障碍物时又是多少 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

Unique Paths

原题链接Unique Paths

计算从左上角有多少条不同的路径可以到达右下角,移动方向只能是向右和向下。

对于每个位置,都有两种移动的可能,即向右移动和向下移动。可以用深度优先(dfs)解决,同时为了解决重复计算,可以用动态规划的思想,记录从dp[i][j]到达右下角有多少条不同的路径。

除了深度优先之外,可以用迭代法执行动态规划,这样做可以减少dp的维度,只需要一维数组即可,不过要改变dp的含义,假设当前所在位置为(m, n),那么dp[n]代表从左上角到达当前位置的不同路径书,原因为

  • 移动方向只能向右和向下,所以只要向下移动一行,就不能再返回上一行。这说明,对于行的记录是可以忽略的。
  • 只要遍历每一行的每一列,不断更新dp[n]直到到达右下角即可,假设当前在第m行的第n列,那么dp[n]表示从左上角开始移动可以有多少条不同的路径达到第m行第n列
  • 对于每个位置,它可以从上一行的当前列向下移动到达当前位置,也可以从当前行的上一列向右移动到达当前位置
  • 所以dp[n] = dp[n] + dp[n - 1],dp[n]代表从上一行的第n列到达右下角的不同路径数,dp[n - 1]代表从当前行的第n-1列到达右下角的不同路径数
  • 直到遍历到右下角,即遍历了所有行所有列,那么dp[n]就代表从左上角到达右下角的不同路径数

代码如下

class Solution { public:int uniquePaths(int m, int n) {/* 到达第0行,第j列的路径数只有1条 */vector<int> dp(n, 1);/* 这里直接忽略了第0行和第0列,原因是到达第0行和第0列的某个位置的路径都只有1条 */for(int i = 1; i < m; ++i){for(int j = 1; j < n; ++j){/* dp[j]表示从左上角到达第i行第j列的不同路径数 *//* 当i为m-1,j为n-1时,就是从左上角到达右下角的不同路径数 */dp[j] = dp[j] + dp[j - 1];}}return dp[n - 1];} };

Unique Paths II

原题链接Unique Paths II

接着上面的问题,如果某些位置有障碍物,那么有多少条路径可以到达右下角。
移动的过程中不能到达障碍物所在的位置。

方法和上面一样,仍然有一维数组记录到达某一列的不同路径,不过需要判断某个位置是否有障碍物,如果有,那么dp[n]为0,否则dp[n] = dp[n - 1] + dp[n]

另外,对于dp[0]要特殊处理,不能像上面一样直接从第一行第一列开始,因为第0行第0列都可能存在障碍物导致dp[n[不是1而是0.

代码如下

class Solution { public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {if(obstacleGrid.empty())return 0;int m = obstacleGrid.size();int n = obstacleGrid[0].size();/* 如果起始位置和目标位置都有障碍物,那么就不可能到达 */if(n == 0 || obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1)return 0;vector<int> dp(n);/* 到达开始位置的路径为1 */dp[0] = 1;/* 到达第0行的某个位置的路径,有障碍物的话后面就都是0,否则是1 */for(int i = 1; i < n; ++i)dp[i] = (obstacleGrid[0][i] == 1) ? 0 : dp[i - 1];for(int i = 1; i < m; ++i){/* 如果当前行的第0列是障碍物,那么到达当前行的第0列的路径数为0 */if(obstacleGrid[i][0] == 1)dp[0] = 0;for(int j = 1; j < n; ++j){dp[j] = obstacleGrid[i][j] == 1 ? 0 : dp[j] + dp[j - 1];}}return dp[n - 1];} };

原题链接Minimum Path Sum

和上面的题一样,只是这回要求是找到路径长度最短的那一条,路径长度是路径上所有数字的和

仍然采用迭代法的动态规划,不过要改变dp的含义,即dp[n]表示从左上角到达当前位置的最小路径长,而不在是不同路径数

另外,第一行和第一列不再单纯的是1,而是数字累加,代表路径长
代码如下

class Solution { public:int minPathSum(vector<vector<int>>& grid) {int m = grid.size();if(m == 0) { return 0; }int n = grid[0].size();if(n == 0) { return 0; }vector<int> dp(n, 0);dp[0] = grid[0][0];/* 这里第一行的路径长要累加 */for(int i = 1; i < n; ++i)dp[i] = dp[i - 1] + grid[0][i];for(int i = 1; i < m; ++i){/* 第一列也要累加 */dp[0] += grid[i][0];for(int j = 1; j < n; ++j){/* 不再是相加,而是找到较小的那个 */dp[j] = std::min(dp[j], dp[j - 1]) + grid[i][j];}}return dp[n - 1];} };

上面三道题主要利用动态规划的思想,另外通过迭代法简化动态规划数组的维度。

总结

以上是生活随笔为你收集整理的每天一道LeetCode-----计算从二维数组的左上角到达右下角的所有路径数及最短的那条,如果存在障碍物时又是多少的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。