当前位置:网站首页>力扣题解 动态规划(2)
力扣题解 动态规划(2)
2022-07-27 05:20:00 【RL-UAV】
343. 整数拆分
- 确定dp数组(dp table)以及下标的含义
dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。
dp[i]的定义讲贯彻整个解题过程,下面哪一步想不懂了,就想想dp[i]究竟表示的是啥!
递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n + 1);
dp[2] = 1;
for (int i = 3; i <= n ; i++) {
for (int j = 1; j < i - 1; j++) {
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
}
}
return dp[n];
}
};
96.不同的二叉搜索树
dp[i] : 1到i为节点组成的二叉搜索树的个数为dp[i]。
也可以理解是i的不同元素节点组成的二叉搜索树的个数为dp[i] ,都是一样的。
p[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量
总结 :j <= i
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n + 1);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
};
01背包问题
即dp[i] [j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
/ weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) {
// 遍历物品
for(int j = 0; j <= bagweight; j++) {
// 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
void test_2_wei_bag_problem1() {
vector<int> weight = {
1, 3, 4};
vector<int> value = {
15, 20, 30};
int bagweight = 4;
// 二维数组
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
// 初始化
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) {
// 遍历物品
for(int j = 0; j <= bagweight; j++) {
// 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[weight.size() - 1][bagweight] << endl;
}
int main() {
test_2_wei_bag_problem1();
}
416. 分割等和子集
- 确定dp数组以及下标的含义
01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值可以最大为dp[j]。
套到本题,dp[j]表示 背包总容量是j,最大可以凑成j的子集总和为dp[j]。
- 确定递推公式
01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
本题,相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。
所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
- dp数组如何初始化
在01背包,一维dp如何初始化,已经讲过,
从dp[j]的定义来看,首先dp[0]一定是0。
如果如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。
这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了。
本题题目中 只包含正整数的非空数组,所以非0下标的元素初始化为0就可以了。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
// dp[i]中的i表示背包内总和
// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
vector<int> dp(10001, 0);
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
}
if (sum % 2 == 1) return false;
int target = sum / 2;
// 开始 01背包
for(int i = 0; i < nums.size(); i++) {
for(int j = target; j >= nums[i]; j--) {
// 每一个元素一定是不可重复放入,所以从大到小遍历
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
// 集合中的元素正好可以凑成总和target
if (dp[target] == target) return true;
return false;
}
};
1049. 最后一块石头的重量 II
总结:在计算target的时候,target = sum / 2 因为是向下取整,所以sum - dp[target] 一定是大于等于dp[target]的。
for(int i = 0; i < weight.size(); i++) {
// 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) {
// 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
vector<int> dp(15001, 0);
int sum = 0;
for (int i = 0; i < stones.size(); i++) sum += stones[i];
int target = sum / 2;
for (int i = 0; i < stones.size(); i++) {
// 遍历物品
for (int j = target; j >= stones[i]; j--) {
// 遍历背包
dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - dp[target] - dp[target];
}
};
494. 目标和
dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
dp[j] += dp[j - nums[i]]
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (abs(S) > sum) return 0; // 此时没有方案
if ((S + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (S + sum) / 2;
vector<int> dp(bagSize + 1, 0);
dp[0] = 1;
for (int i = 0; i < nums.size(); i++) {
for (int j = bagSize; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[bagSize];
}
};
- 时间复杂度:O(n × m),n为正数个数,m为背包容量
- 空间复杂度:O(m),m为背包容量
474.一和零
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0)); // 默认初始化0
for (string str : strs) {
// 遍历物品
int oneNum = 0, zeroNum = 0;
for (char c : str) {
if (c == '0') zeroNum++;
else oneNum++;
}
for (int i = m; i >= zeroNum; i--) {
// 遍历背包容量且从后向前遍历!
for (int j = n; j >= oneNum; j--) {
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
return dp[m][n];
}
};
边栏推荐
- 制作视频特效必备工具:NUKE 13
- 使用Markdowm
- Day 2. Depressive symptoms, post-traumatic stress symptoms and suicide risk among graduate students
- [first song] Introduction to data science of rebirth -- return to advanced level
- 编程学习记录——第9课【操作符】
- 判断是否为回文结构的三种方法
- 【头歌】重生之我在py入门实训中(1)
- [high concurrency] interviewer
- Cmder的基础文件操作
- [first song] rebirth of me in py introductory training (2): formula programming
猜你喜欢

QGIS系列(1)-QGIS(server-apache) win10安装

Chrome 如何快速将一组正在浏览的网页(tabs)转移到另一台设备(电脑)上

李宏毅 2020 深度学习与人类语言处理 DLHLP-Conditional Generation by RNN and Attention-p22

Multi task foundation of IOT operating system

arcgis for js api(2) 获取要素服务的id集合

STM32-FSMC外扩内存SRAM

pycharm安装及导入项目注意事项

超强远程连接管理工具:Royal TSX

Day 3. Suicidal ideation and behavior in institutions of higher learning: A latent class analysis

Live Home 3D Pro interior home design tool
随机推荐
Live Home 3D Pro室内家居设计工具
谈谈为何需要将类的成员函数声明为private
【头歌】重生之我在py入门实训中(7): 函数调用
韦东山 数码相框 项目学习(一)在LCD上显示ASCII字符
[first song] rebirth of me in py introductory training (1)
力扣 110. 平衡二叉树
Day 3. Suicidal ideation and behavior in institutions of higher learning: A latent class analysis
C#文件的读写
编程学习记录——递归解决汉诺塔问题
剪枝-量化-转onnx中文系列教程
geonode geoserver win10 安装教程(亲测)
[song] rebirth of me in py introductory training (12): Matplotlib interface and common graphics
使用Markdowm
力扣题解 二叉树(5)
Chrome 如何快速将一组正在浏览的网页(tabs)转移到另一台设备(电脑)上
System Design的相关准备材料
Weidongshan digital photo frame project learning (III) transplantation of freetype
非重叠矩形中的随机点(力扣每日一题)
Can it replace PS's drawing software?
Live Home 3D Pro interior home design tool