🔥博客介绍`: 27dCnc
🎥系列专栏: <<数据结构与算法>> << 算法入门>> << C++项目>>
🎥 当前专栏: << 算法入门>>
专题 : 数据结构帮助小白快速入门算法
👍👍👍👍👍👍👍👍👍👍👍👍
☆*: .。. o(≧▽≦)o .。.:*☆
❤️感谢大家点赞👍收藏⭐评论✍️
学习目标:
今日学习打卡
- 代码随想录 - 动态规划
学习时间:
- 周一至周五晚上 7 点—晚上9点
- 周六上午 9 点-上午 11 点
- 周日下午 3 点-下午 6 点
学习内容:
- 不同路径
- 不同路径 II
- 整数拆分
内容详细:
62.不同路径
考点: 动态规划
数学
深度优先搜索(dfs)
解题思路
高中时候的组合规律,当然我们不能直接这样写我们要进行动态规划分析
首先看到题目是想到dfs
class Solution {
private:
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);
}
public:
int uniquePaths(int m, int n) {
return dfs(1, 1, m, n);
}
};
但是超时
开始动态规划
- 确定dp数组以及下标的含义
dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[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]只有这两个方向过来。
- dp数组的初始化
这个就是高中的知识点
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
- 确定遍历顺序
这里要看一下递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的。
- 举例推导dp数组
最终代码
class Solution {
public:
int uniquePaths(int m, int n) {
int dp[m][n];
dp[0][0] = 0;
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];
}
}
return dp[m - 1][n - 1];
}
};
63. 不同路径 II
题目考点: 动态规划
解题思路
和上一题一样,只是多了障碍物,可以直接跳过,
如果遇到障碍物 continue
if (obstacleGrid[i][j] == 1) {continue;}
i 代码
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int l,r;
int m =obstacleGrid.size();
int n = obstacleGrid[0].size();
int dp[m][n];
if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1){
return 0;
}
memset(dp,0,sizeof(dp));
for (int i = 0; i < m && !obstacleGrid[i][0]; i++) dp[i][0] = 1;
for (int j = 0; j < n && !obstacleGrid[0][j]; 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];
}
};
ii 代码
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if (obstacleGrid[0][0] == 1)
return 0;
vector<int> dp(obstacleGrid[0].size());
for (int j = 0; j < dp.size(); ++j)
if (obstacleGrid[0][j] == 1)
dp[j] = 0;
else if (j == 0)
dp[j] = 1;
else
dp[j] = dp[j-1];
for (int i = 1; i < obstacleGrid.size(); ++i)
for (int j = 0; j < dp.size(); ++j){
if (obstacleGrid[i][j] == 1)
dp[j] = 0;
else if (j != 0)
dp[j] = dp[j] + dp[j-1];
}
return dp.back();
}
};
343. 整数拆分
题目考点: 动态规划
解题思路
可以拆分成多个数据对动态规划实行贪心,max就是贪心的具象化,(个人理解)
其他步骤省,这里详细讲解
- 确定递推公式
可以想 dp[i]最大乘积是怎么得到的呢?
其实可以从1遍历j,然后有两种渠道得到dp[i].
一个是j * (i - j) 直接相乘。
一个是j * dp[i - j],相当于是拆分(i - j),对这个拆分不理解的话,可以回想dp数组的定义。
那有同学问了,j怎么就不拆分呢?
j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。
递推公式:
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。
-
如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。
-
所以递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});
-
那么在取最大值的时候,为什么还要比较dp[i]呢?
因为在递推公式推导的过程中,每次计算dp[i],取最大的而已。
class Solution {
public:
int integerBreak(int n) {
if(n < 4) return n/2 * (n - n/2);
int dp[n+4];
memset(dp,0,sizeof dp);
dp[2] = 1;
for (int i = 3; i <= n ; i++) {
for (int j = 1; j <= i / 2; j++) {
dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});
}
}
return dp[n];
}
};
学习产出:
- 技术笔记 2 遍
- CSDN 技术博客 3 篇
- 习的 vlog 视频 1 个
重磅消息:
GTP - 4 最新版接入服务他来了 点击链接即可查看详细
GTP - 4 搭建教程文章来源:https://www.toymoban.com/news/detail-838681.html
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~文章来源地址https://www.toymoban.com/news/detail-838681.html
到了这里,关于我在代码随想录|写代码Day33 | 动态规划| 路径问题| 62.不同路径,63. 不同路径 II,343. 整数拆分的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!