LeetCode 62 不同路径
题目链接:https://leetcode.cn/problems/unique-paths/
思路:
使用动态规划五部曲:
使用一个二维数组dp[i][j],代表第(i,j)位置上有多少个路径
确定递推公式:
想要求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]。
此时在回顾一下 dp[i - 1][j] 表示啥,是从(0, 0)的位置到(i - 1, j)有几条路径,dp[i][j - 1]同理。
那么很自然,dp[i][j] = dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来。
递归数组初始化
显然,第一行和第一列的每个位置都只有一条路径能到达,所以:
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1
确定遍历顺序
因为后面的值要用到前面的值,所以显然是从前往后遍历
代码:
class Solution {
public:
int uniquePaths(int m, int n) {
if(m==1&n==1) return 1;
vector<vector<int>>dp(m,vector<int>(n));
for(int i = 1;i<n;i++)
dp[0][i] = 1;
for(int i = 1;i<m;i++)
dp[i][0] = 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];
}
};
总结
使用动规五部曲,轻松解决。要注意边界条件。
LeetCode 63 不同路径 II
题目链接:https://leetcode.cn/problems/unique-paths-ii/
思路:
思路和62.不同路径相类似,只是此时有了障碍就需要注意,如果障碍在第一行或者第一列中,初始化dp数组时,出现障碍的位置之后都为0.
代码:
自写
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));
if(obstacleGrid[0][0]==1) return 0;
if(m==1&&n==1&&obstacleGrid[0][0]==0) return 1;
for(int i = 1;i<n;i++)
{
if(obstacleGrid[0][i]==1)
{
while(i<n)
{
dp[0][i] = 0;
i++;
}
break;
}
else
dp[0][i] = 1;
}
for(int i = 1;i<m;i++)
{
if(obstacleGrid[i][0]==1)
{
while(i<m)
{
dp[i][0] = 0;
i++;
}
break;
}
else
dp[i][0] = 1;
}
for(int i = 1;i<m;i++)
{
for(int j = 1;j<n;j++)
{
if(obstacleGrid[i][j]==1)
continue;
else
dp[i][j] = dp[i][j-1]+dp[i-1][j];
}
}
// for(int i = 0;i<dp.size();i++)
// {
// for(int j = 0;j<dp[0].size();j++)
// cout<<dp[i][j]<<" ";
// cout<<endl;
// }
// cout<<endl;
return dp[m-1][n-1];
}
};
卡哥代码
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
//如果在起点或终点出现了障碍,直接返回0
if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1)
return 0;
vector<vector<int>> dp(m, vector<int>(n, 0));
// 如果在第一行或者第一列出现了障碍那么就让后面的数保持为0
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1) continue;
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
};
总结
想法和代码都可以写出来,但是自己写的代码非常的冗杂。需要学习卡哥写的代码。
今日总结:
动规五部曲的应用,相对简单。