LeetCode——63. Unique Paths II

1.题目大意

以一个由0与1组成的矩阵为地图,1为障碍,从左上角到右下角有多少条路径。注意,只能到向下或者向右移动。

2.解题方法

以矩阵[[0, 0, 0], [0, 1, 0], [0, 0, 0]]为例,很显然,这个地图中从(0, 0)到(2, 2)只有两条路径。依据动态规划的思路,我们可以把从(0, 0)到(2, 2)的路径数量等同于(0, 0)到(2, 1)的路径数量以及(0, 0)到(1, 2)的路径数量之和,把大问题分解为小问题,一步一步的化解为最简单的能直接知道答案的小问题,然后把这些小问题的答案组合起来就是大问题的答案了。

所以,从(0, 0)到每个节点的路径数量是它上面一个节点的路径数量以及它右边节点的路径数量之和,当然,如果这个节点有障碍,那么这个节点就不可抵达,即路径数量为0。再考虑边界问题后,就可以编写以下代码:

class Solution {
public:
	int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
		int m = obstacleGrid.size() - 1;
		int n = obstacleGrid.at(0).size() - 1;
		// 如果开始节点(0, 0)以及目标节点(m, n)都有障碍,那么可以直接返回0了。
		if (obstacleGrid.at(0).at(0) == 1 || obstacleGrid.at(m).at(n) == 1)
			return 0;
		return sub(obstacleGrid, m, n);
	}

	// 将求从节点(0, 0)到节点(m, n)的路径数量变为求从节点(0, 0)到节点(m - 1, n)以及到节点(m, n - 1)的路径数量之和。
	// 当然,如果m == 0或者n == 0,就不用求什么数量之和了,直接求到该节点的上一个节点或者左边节点的路径数量即可了。 
	int sub(vector<vector<int>>& subGrid, int m, int n) {
		int topIndex = m - 1;
		int leftIndex = n - 1;
		if (m > 0 && n > 0) {
			int top = subGrid.at(topIndex).at(n);
			int left = subGrid.at(m).at(leftIndex);
			if (top == 0 && left == 0)
				return sub(subGrid, m - 1, n) + sub(subGrid, m, n - 1);
			if (top == 0)
				return sub(subGrid, m - 1, n);
			if (left == 0)
				return sub(subGrid, m, n - 1);
			return 0;
		}
		else if (n == 0 && m > 0) {
			int top = subGrid.at(topIndex).at(n);
			if (top == 0)
				return sub(subGrid, m - 1, 0);
			return 0;
		}
		else if (m == 0 && n > 0) {
			int left = subGrid.at(m).at(leftIndex);
			if (left == 0)
				return sub(subGrid, 0, n - 1);
			return 0;
		}
		return 1;
	}
};

虽然,很明显的,这个解题思路是正确的,但由于使用的是递归,所以,time limit error了。
所以,我们要将这个递归化解为循环,我们可以直接用一个二维数组来达到相同的结果了。只要令下标为[i][j]的元素的值(即路径数量)为下标为[i - 1][j]的元素以及下标为[i][j - 1]的元素之和,再考虑考虑边界问题,就可以了。

class Solution {
public:
	int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
		int m = obstacleGrid.size();
		int n = obstacleGrid.at(0).size();
		int matrix[m][n] = {0};
		matrix[0][0] = 1;
		for (int i = 0; i < m; i = i + 1) {
			for (int j = 0; j < n; j = j + 1) {
				if (obstacleGrid.at(i).at(j) == 1)
					matrix[i][j] = 0;
				else if (i > 0 && j > 0)
					matrix[i][j] = matrix[i - 1][j] + matrix[i][j - 1];
				else if (i > 0)
					matrix[i][j] = matrix[i - 1][j];
				else if (j > 0)
					matrix[i][j] = matrix[i][j - 1];
			}
		}
		return matrix[m - 1][n - 1];
	}
};

那么,还有没有更简单的方法呢?答案是有的,一个二维数组的地图如下:

[
	[0, 0, 0],
	[0, 1, 0],
	[0, 0, 0],
	[0, 0, 0]
]

用二维数组求解的话,那么二维数组就如下:

[
	[1, 1, 1],
	[1, 0, 1],
	[1, 1, 2],
	[1, 2, 4]
]

可以观察到每个元素都是左边以及右边元素的值的和,除了障碍点。所以,用一维数组来替代二维数组也是可能的,因为在再一次遍历更新这个数组时,更新到的第i个元素还保留着上一行的i下标的值,相当于二维数组上边的值,而左边已经更新了,相当于二维数组左边的值了,所以可以直接将matrix[i - 1]的值加到matrix[i]上,效果也是一样的。

class Solution {
public:
	int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
		int m = obstacleGrid.size();
		int n = obstacleGrid.at(0).size();
		int matrix[n]= {0};
		matrix[0] = 1;
		for (int i = 0; i < m; ++i) {
			vector<int> v = obstacleGrid.at(i);
			for (int j = 0; j < n; ++j) {
				if (v.at(j))
					matrix[j] = 0;
				else if (j > 0)
					matrix[j] += matrix[j - 1];
			}
		}
		return matrix[n - 1];
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值