动态规划五步曲
1.确定dp及dp[i]的含义
2.找出递推公式
3.确定dp数组如何初始化
4.确定遍历顺序
5.打印dp数组验证
一、不同路径
思路:动态规划
由题意易知,dp数组需要使用二维。
- 1.确定dp数组以及dp[i][j]的含义
dp[i][j]的含义是:到达下标i,j位置有dp[i][j]种路径
- 2.递推公式
由题意我们可以知道,机器人只能向右走或者向下走,所以只有两种情况能走到dp[i][j]位置,如下图:
即:dp[i-1][j]往下走一步就能到达dp[i][j]位置,或者dp[i][j-1]往右走一步就能达到dp[i][j]位置。
所以到达dp[i][j]位置有:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
注意这里存在一个误区:可能你会觉得
dp[i][j] = dp[i-1][j]+1+dp[i][j-1] + 1
产生这样想法的原因是你没有搞清楚dp[i][j]的含义是什么
dp[i][j]的含义是到达下标i,j位置有多少种路径,而不是走了多少步,如果是走了多少步,那么就可以从dp[i-1][j]往下+1,或者dp[i][j-1]往右+1。
- 3.如何进行初始化
我们知道,从dp[0][0]位置开始的第一行和第一列的任意位置,都只有一种方法能够到达。
因为只能向右走或者向下走,比如到达dp[0][5]位置,只能有一条路径可以到达。
所以第一行和第一列的所有位置都需要初始化成1。
- 4.确定遍历顺序
根据题意可知,dp数组是需要从左到由从上到下遍历的。 - 5.打印dp数组进行验证
具体代码如下:
//动态规划五步曲:
//1.确定dp[i][j] 的含义:
//到达dp[i][j] 位置一共有多少种不同路径
//2.确定递推公式
//dp[i][j] = dp[i-1][j] + dp[i][j-1];
//到dp[i-1][i]的路径量+到dp[i][j-1]的路径量。
//3.确定如何初始化
//最左边一行和最上边一行全部初始化成1,因为题目要求只能向下或者向右移动一步最上边一行到任意位置只有一种路径,最左边一行到任意位置也只有一种路径。
//4.确定遍历顺序,由题意可知,只能从左到右,从上到下进行遍历。
//5.打印dp数组的值
class Solution {
public:
int uniquePaths(int m, int n)
{
int dp[m][n];
for(int i = 0;i<m;++i)
{
dp[i][0] = 1;
}
for(int j = 0;j<n;++j)
{
dp[0][j] = 1;
}
for(int i = 1;i<m;++i)
{
for(int j = 1;j<n;++j)
{
dp[i][j] = dp[i-1][j] + dp[i][j-1];
printf("%d ",dp[i][j]);
}
}
return dp[m-1][n-1];
}
};
时间复杂度O(m*n),空间复杂度O(m*n)
二、不同路径(升级版)
思路:动态规划
大致的情况与第一题相同,只不过在路上会遇到障碍物。
有障碍物的位置为1,没有障碍物的位置为0。
但是在初始化的地方和递归的过程是有一点不同的。
在初始化时:
该情况,当我们在第一行或者第一列的初始化位置遇到障碍物时
在障碍物以及之后的所有位置,都不能被初始化,因为一旦遇到障碍物,就没有办法继续往后走了。
还有一种情况是:障碍物在起点或者终点,都无法获取路径,直接返回0即可。
所以在初始化的时候我们应该这样写代码:
//初始化有障碍物,遇到障碍物及其之后的位置不能再初始化成1了,就跳过
for(int i = 0;i < m && obstacleGrid[i][0] != 1;++i)
{
dp[i][0] = 1;
}
for(int j = 0;j<n && obstacleGrid[0][j] != 1;++j)
{
dp[0][j] = 1;
}
2.在进行递推时
如果我们在如图所示的地方遇到了障碍物,我们就不能再递推了,就需要直接跳过该位置。(且题目的意思,障碍物的地方路径数是0)
所以我们应该这样写代码:
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];
}
}
具体代码如下:
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));
//初始化有障碍物,遇到障碍物及其之后的位置不能再初始化成1了,就跳过
for(int i = 0;i < m && obstacleGrid[i][0] != 1;++i)
{
dp[i][0] = 1;
}
for(int j = 0;j<n && obstacleGrid[0][j] != 1;++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];
}
};
时间复杂度O(m*n),空间复杂度O(m*n)
总结
今天写了动态规划不同路径,我发现跟着b站大佬的学习视频学动态规划特别爽~
继续干动态规划!