leetcode 第 64 题:最小路径和(C++)

64. 最小路径和 - 力扣(LeetCode)

和这一题特别像:LeetCode第 120 题:三角形最小路径和(C++)_qq_32523711的博客-CSDN博客

动态规划典型题目,状态方程如下

非边界,当i、j 均不为0时:

f [ i ] [ j ] = m i n ( f [ i ] [ j − 1 ] , f [ i − 1 ] [ j ] ) + g r i d [ i ] [ j ] f[i][j] = min(f[i][j-1], f[i-1][j]) + grid[i][j] f[i][j]=min(f[i][j1],f[i1][j])+grid[i][j]

f [ 0 ] [ 0 ] = g r i d [ 0 ] [ 0 ] f[0][0] = grid[0][0] f[0][0]=grid[0][0]

边界时(左边界j=0,上边界i=0)

f [ i ] [ 0 ] = f [ i − 1 ] [ 0 ] + g r i d [ i ] [ 0 ] f[i][0] = f[i-1][0] + grid[i][0] f[i][0]=f[i1][0]+grid[i][0]

f [ 0 ] [ i ] = f [ 0 ] [ i − 1 ] + g r i d [ 0 ] [ i ] f[0][i] = f[0][i - 1] + grid[0][i] f[0][i]=f[0][i1]+grid[0][i]

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
	    int row = grid.size();
	    int col = grid[0].size();
	    vector<vector<int>> f(row, vector<int>(col, 0));
	    f[0][0] = grid[0][0];
	    for (int i = 1; i < row; ++i) //左边界
		    f[i][0] = f[i - 1][0] + grid[i][0];
	    for (int i = 1; i < col; ++i) //上边界
		    f[0][i] = f[0][i - 1] + grid[0][i];
	    for (int i = 1; i < row; ++i){ //其他
		    for (int j = 1; j < col; ++j)
			    f[i][j] = min(f[i][j - 1], f[i - 1][j]) + grid[i][j];
	    }
	    return f[row - 1][col - 1];
    }
};

换个写法,思路更加清晰:

第一次循环,根据第一行的左边界f[0][0](已知)计算出第一行的剩余元素;

剩下的每一次循环之前,先计算当前行的左边界元素,然后根据左边界元素和上一行元素,计算出当前行的剩余元素。

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
	    int row = grid.size();
	    int col = grid[0].size();
	    vector<vector<int>> f(row, vector<int>(col, 0));
	    f[0][0] = grid[0][0];
        
	    for (int i = 0; i < row; ++i){//先考虑行
            if(i != 0) f[i][0] = f[i-1][0] + grid[i][0];  //计算当前行的左边界元素
		    for (int j = 1; j < col; ++j){
                if(i == 0) //如果是上边界(第一行)
                    f[0][j] = f[0][j - 1] + grid[i][j];
                else
                    f[i][j] = min(f[i][j - 1], f[i - 1][j]) + grid[i][j];
            }
	    }
	    return f[row - 1][col - 1];
    }
};

可以看到空间复杂度为O(m*n),为辅助数组的占用空间。

下面进行一下优化吧,由状态方程可以看到,每一行的元素值只与该行元素和上一行元素有关,所以其实不需要n x m的额外空间(和这个类似:LeetCode第 120 题:三角形最小路径和(C++)_qq_32523711的博客-CSDN博客)。

一般这种情况我们可以使用滚动数组减少空间消耗,两行(2xn)交替使用就可以,更甚,其实一行(1xn)就可以

直接考虑一行(1xn),代码:

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int row = grid.size();
	    int col = grid[0].size();
	    vector<int> f(col, 0);

	    for (int i = 0; i < row; ++i){
            f[0] = f[0] + grid[i][0]; //左边界f[0](第一列)
		    for (int j = 1; j < col; ++j){
                if(i == 0) //如果是上边界(第一行)
                    f[j] = f[j-1] + grid[i][j];
                else
                    f[j] = min(f[j - 1], f[j]) + grid[i][j];
            } 
	    }
	    return f[col - 1];
    }
};

滚动数组(2xn)的也写一下:

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
	    int row = grid.size();
	    int col = grid[0].size();
	    vector<vector<int>> f(2, vector<int>(col, 0));
	    f[0][0] = grid[0][0];
        
        int cur; //滚动数组下标
        int pre; //滚动数组下标
	    for (int i = 0; i < row; ++i){//先考虑行
            cur = i % 2; //要么1要么0)
            pre = 1-cur; //要么0要么1
            if(i != 0) f[cur][0] = f[pre][0] + grid[i][0];  //计算当前行的左边界元素
		    for (int j = 1; j < col; ++j){
                if(i == 0) //如果是上边界(第一行)
                    f[cur][j] = f[cur][j - 1] + grid[i][j];
                else
                    f[cur][j] = min(f[cur][j - 1], f[pre][j]) + grid[i][j];
            }
	    }
	    return f[cur][col - 1];
    }
};

更奇葩的也还有,空间复杂度O(1),直接在原数组上修改就行(因为每个数只会用到一次),思路和第一段代码一样,只是存储的时候稍作修改即可。。。不过,个人不是很推荐,修改原数组毕竟不太好。。吧。。。

这个题使用回溯的思路也是可以的,而且剪枝也简单(路径和大于当前最小路径和就直接cut掉)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值