最小路径和

100 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

题目描述

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小,并且,每次只能向右或者向下移动。

思路分析

此题目思考方法同上一篇《动态规划路径问题(一)----不同路径》juejin.cn/post/717250…

  1. 由于要求最小路径和,所以需要定义一个二维数组来记录起点到当前每个节点的最小路径和
  2. 由于节点可以向下和向右移动,那么计算当前节点可能产生的路径和就可以分为两种情况:1.左节点最小路径和+当前节点路径值 2.上节点最小路径和+当前节点路径值 。 那么当前节点的最小路径和,即在以上两种情况中选取最小值
  3. 在实际对网格的遍历过程中会产生如下三种情况:1.当前节点存在左节点和上节点,此时当前节点最小路径和=min(上节点最小路径和+当前节点路径值,左节点最小路径和+当前节点路径值) ; 2. 当前节点只有左节点而没有上节点,即节点在第一行时,当前节点最小路径值=左节点最小路径值+当前节点路径值 ; 3.当前节点只有上节点而没有左节点,即节点在第一列时,当前节点最小路径值=上节点最小路径值+当前节点路径值

代码实现

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        //获取网格的行和列
        int row=grid.size(),col=grid[0].size();
        //定义已知大小的动态二维数组,记录到当前节点的最小路径和
        vector<vector <int>> dpsum(row, vector<int>(col, 1));
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                //当遍历起点时,进行路径和的初始化
                 if(i==0&&j==0) 
                    dpsum[i][j]=grid[i][j];
                 //当遍历中间节点时,右左节点和上节点
                 else if(i>0&&j>0)
                    dpsum[i][j]=min(dpsum[i-1][j]+grid[i][j],dpsum[i][j-1]+grid[i][j]);
                //遍历第一列时,只有上一个节点的最小路径和
                 else if(i>0)
                    dpsum[i][j]=dpsum[i-1][j]+grid[i][j];
                //遍历第一行,只能记录左侧节点的最小路径和
                 else if(j>0)
                    dpsum[i][j]=dpsum[i][j-1]+grid[i][j];  
                //当前节点的路径和=左节点路径和+当前值 与 上节点路径和+当前值  两者取最小值
            }
        }
        //返回终点处的最小路径和
        return dpsum[row-1][col-1]; 
    }
};

知识补充

  //定义二维的vector容器
   vector<vector <int>> dpsum(row, vector<int>(col, 1));

思考???

  1. 如果方块中「存在负权」,如何求解? 如果只是增加负权值的条件,走动规则不变(只能往下或往右),那么 DP 仍然有效。仍然能够得到「总成本最小」的路径,但不确保成本必然为负权,也不确保必然会经过负权位置。

  2. 如果走动规则调整为「可以往任意方向」且「每个位置最多只能访问一次」,如何求解? 这时候问题就转换为「图论最短路」问题,而且是从「特定源点」到「特定汇点」的「单源最短路」问题。需要根据是否存在「负权边」来分情况讨论:

    • 不存在负权边:使用 Dijkstra 算法求解
    • 存在负权边:使用 Bellman Ford 或 SPFA 求解 leetcode.cn/leetbook/re…