LeetCode/最小路径和

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

1. 动态规划

将问题转化成子问题的方程(递归重复计算耗时过多,以后不再使用反向递归)
状态转移函数:最小路径长度dp[m][n]=min(dp[m-1][n],dp[m][n-1])+grid[m][n]
边界条件:dp[i][0]=0、dp[0][i]=0

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if (grid.size() == 0 || grid[0].size() == 0) return 0;

        int rows = grid.size(), columns = grid[0].size();//得到行数和列数
        auto dp = vector < vector <int> > (rows, vector <int> (columns));//初始化dp数组
        dp[0][0] = grid[0][0];//边界
        //!!!由于实际使用中数组零下标存放了数据,不能用于初始化边界0,故直接算出两条存有数据的新边界
        for (int i = 1; i < rows; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];//算出第一列路径长度(边界)
        }
        for (int j = 1; j < columns; j++) {
            dp[0][j] = dp[0][j - 1] + grid[0][j];//算出第一行路径长度(边界)
        }
        for (int i = 1; i < rows; i++) {
            for (int j = 1; j < columns; j++) {//一行一行或一列一列从前往后算都可以
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[rows - 1][columns - 1];
    }
};

2. 动态规划一维优化

由于必须要遍历整个grid二维数组,才能得出最小路径,时间复杂度最小为O(n2),无法再进行优化
仔细观察方法一,发现进行参数更新的时候,只与前一列(行)同位置元素有关,更新后之前的数据就没用了
所以我们可以用一维数组对dp进行存储,只是要注意参数更新时候的位置,可以使空间复杂度减小为O(n)

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if (grid.size() == 0 || grid[0].size() == 0) return 0;

        int rows = grid.size(), columns = grid[0].size();//得到行数和列数

        vector<int> dp(columns); //一维数组存储一行的数据
    
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {//一行一行进行参数更新
                if(i==0&&j==0)
                    dp[j]=grid[i][j];  //初始点赋原值
                else if(i==0&&j!=0)  //第一行的参数更新
                    dp[j]=grid[i][j]+dp[j-1];
                else if(i!=0&&j==0)  //第一列的参数更新情况发生变化,因为前面没参数
                    dp[j]=grid[i][j]+dp[j];//只能由上一行进行转移
                else //既能由上转移又能由左转移的情况
                    dp[j] = min(dp[j-1], dp[j]) + grid[i][j];
            }
        }
        return dp[columns - 1];
    }
};

3. 回溯法

相当于使用深度优先的方式,通过递归右和下方向,遍历所有路径,同一个节点被多条路径重复遍历,时间复杂度非常高
事前要声明全局变量最小路径和,以便不同路径比较得出最小路径,这里给出一个框架

点击查看代码
int min_sum = INT_MAX;//全局变量赋一个极大值
    void dfs(vector<vector<int>>& grid,int row,int col,int sum){
        if(超出递归边界)  return;
        sum+=grid(row,col); //路径权值加入路径和
        if(达到路径终点) {
            min_sum = min(min_sum,sum);
            return;
        }
        dfs(grid,row+1,col,sum);//递归往右移动
        //跳出递归后相当于取消向右移动,进行了一次回溯
        dfs(grid,row,col+1,sum);//递归往下移动
}
posted @ 2022-05-11 23:31  失控D大白兔  阅读(39)  评论(0编辑  收藏  举报