目录
62. 不同路径
问题描述:
实现代码与解析:
深度优先(超时):
原理思路:
动态规划:
原理思路:
数学方法:
原理思路:
63. 不同路径 II
问题描述:
实现代码与解析:
动态规划:
原理思路:
62. 不同路径
问题描述:
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
输入:m = 3, n = 7 输出:28
示例 2:
输入:m = 3, n = 2 输出:3 解释: 从左上角开始,总共有 3 条路径可以到达右下角。 1. 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 3. 向下 -> 向右 -> 向下
示例 3:
输入:m = 7, n = 3 输出:28
示例 4:
输入:m = 3, n = 3 输出:6
实现代码与解析:
深度优先(超时):
class Solution {
public:
int dfs(int i, int j, int m, int n)
{
if (i > m || j > n) return 0; // 越界
if (i == m && j == n) return 1; // 找到一条路径
return dfs(i + 1, j, m, n) + dfs(i, j + 1, m, n);
}
int uniquePaths(int m, int n)
{
return dfs(1, 1, m, n);
}
};
原理思路:
可以看成是二叉树,深度优先遍历,不过这个方法会超时。
动态规划:
class Solution {
public:
int uniquePaths(int m, int n)
{
vector<vector<int>> dp(m,vector<int>(n));//dp数组,含义:到i,j位置的路径个数
for(int i=0;i<m;i++) dp[i][0]=1;//第一列初始化
for(int i=0;i<n;i++) dp[0][i]=1;//第一行初始化
for(int i=1;i<m;i++)
{
for(int j=1;j<n;j++)
{
dp[i][j]=dp[i][j-1]+dp[i-1][j];//递推公式
}
}
return dp[m-1][n-1];
}
};
原理思路:
动态规划的经典题目,这里题目描述每次只能向下和向右走,dp数组含义是到[i,j]位置可以走的路径条数,理解了这个便很好写出递推的公式了,便是从上位置来的路径和从左位置来的路径之和了,还有dp的初始化,第一列和第一行显然都只有一条路线可以到达,初始化为1。
数学方法:
class Solution {
public:
int uniquePaths(int m, int n) {
long long result = 1;
for (int x = n, y = 1; y < m; ++x, ++y)
{
result = result * x / y;
}
return result;
}
};
原理思路:
有点概率论那意思,根据题目我们可以判断出要到达终点一共要走 m + n - 2步,其中 m - 1 步是向下走的,所以很容易写出公式:
注意算的时候,不要把分子分母都算出来再除,很容易超过范围,要一边乘一边除。
63. 不同路径 II
问题描述:
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1
和 0
来表示。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2
条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
示例 2:
输入:obstacleGrid = [[0,1],[0,0]] 输出:1
实现代码与解析:
动态规划:
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));//dp数组
//dp初始化,第一行
for(int i = 0; i < n; i++)
{
if(obstacleGrid[0][i] == 1)
{
break;
}
dp[0][i] = 1;
}
//dp第一列列初始化
for(int i = 0; i < m; i++)
{
if(obstacleGrid[i][0] == 1)
{
break;
}
dp[i][0] = 1;
}
//开始遍历
for(int i = 1; i < m; i++)
{
for(int j = 1; j < n; j++)
{
//注意这里,空位置才求路径,有障碍物不算路径,不然后面的路径推导肯定出现错误
if(obstacleGrid[i][j] == 0)
{
dp[i][j]=dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
};
原理思路:
动态规划,此题与上一题的区别就是多了障碍物而已,原理相似,只是需要注意一些区别和细节,比如dp初始化,我们第一行和第一列在没有遇到障碍物时赋值为1,因为一但有障碍物,其后面的格子肯定是过不去的,此题只能向右和下走。还有就是递推公式,我们在空位置才递推,不然在有障碍物的地方也计算路径的话,后面空位置递推出来的路径一定是有错误的。