领扣:矩阵最小路径和

描述

给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径。

Tip: 你在同一时间只能向下或者向右移动一步

样例
样例 1:
输入: [[1,3,1],[1,5,1],[4,2,1]]
输出: 7

样例解释:
路线为: 1 -> 3 -> 1 -> 1 -> 1。

样例 2:
输入: [[1,3,2]]
输出: 6

解释:  
路线是: 1 -> 3 -> 2

解答

有两种方案可以实现:

  1. 采用递归,实现简单,但是数据大时性能弱。
  2. 采用广度优先搜索方式,性能较好。
class Solution {
public:
    /**
     * @param grid: a list of lists of integers
     * @return: An integer, minimizes the sum of all numbers along its path
     */
    int minPathSum(vector<vector<int>> &grid) {
        // write your code here
        
        if(grid.empty()){
            return 0;
        }
        
        //return minPath(grid, 0, 0);
        return minPath(grid);
    }
    
    // 递归方式搜索----数量大时,性能较弱。
    int minPath(vector<vector<int>> &grid, int i, int j)
    {
        // 终点
        if( i == grid.size() - 1 && j == grid[0].size() - 1)
        {
            // 输出路径表
            return grid[i][j];
        }
        
        int nRight = 0x7FFFFFFF;
        if(j + 1 < grid[0].size()){
            // 将(i,j + 1)加入路径表
            nRight = minPath(grid, i , j + 1);
            // 将(i,j + 1)移出路径表
        }
        int nDown = 0x7FFFFFFF;
        if(i + 1 < grid.size()){
            // 将(i + 1,j)加入路径表
            nDown = minPath(grid, i + 1, j);
            // 将(i + 1,j)移出路径表
        }
        
        return std::min(nRight, nDown) + grid[i][j];
    }
    
    // 广度优先搜索
    int minPath(vector<vector<int>> &grid)
    {
        int m = grid.size();
    	int n = grid[0].size();
        
        // 构造两个临时容器
        // arr用于存储当前点的最小路径和
        // tmp用于存储当前点是否已被加入到队列
    	vector<vector<int>> arr = grid;
    	vector<vector<int>> tmp = grid;
        // 赋值为均未加入到队列初始状态
    	for (int i = 0; i < m; i++)
    	{
    		for (int j = 0; j< n; j++)
    		{
    			tmp[i][j] = 0;
    		}
    	}
    
    	struct positon
    	{
    		int x;
    		int y;
    	};
    
    	std::queue<positon> p;
    	// 加入起点
    	p.push(positon{ 0, 0 }); 
    	tmp[0][0] = 1;
    
    	int nUp = 0;
    	int nLeft = 0;
    	while (p.size())
    	{
    		positon& frn = p.front();
    
    		// 从左边走过来的距离
    		if (frn.y > 0) {
    			nLeft = arr[frn.x][frn.y - 1];
    		}
    		else {
    			nLeft = 0x7FFFFFFF;
    		}
    		// 从上边走过来的距离
    		if (frn.x > 0) {
    			nUp = arr[frn.x - 1][frn.y];
    		}
    		else {
    			nUp = 0x7FFFFFFF;
    		}
    		// 取两者最小
    		if (nLeft != 0x7FFFFFFF || nUp != 0x7FFFFFFF) {
    			arr[frn.x][frn.y] = grid[frn.x][frn.y] + min(nLeft, nUp);
    		}
    		else {
    			arr[frn.x][frn.y] = grid[frn.x][frn.y];
    		}
    		// 右 下节点加入队列,若已被加入过,则不加入,否则指数型增长
    		if (frn.y < n - 1 && tmp[frn.x][frn.y + 1] != 1) {
    			tmp[frn.x][frn.y + 1] = 1;
    			p.push(positon{ frn.x, frn.y + 1 });
    		}
    		if (frn.x < m - 1 && tmp[frn.x + 1][frn.y] != 1) {
    			tmp[frn.x + 1][frn.y] = 1;
    			p.push(positon{ frn.x + 1, frn.y });
    		}
    		//队顶出队
    		p.pop();
    	}
    	
        return arr[m - 1][n - 1];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值