代码随想录算法训练营第31天|1049.最后一块石头的重量II、494.目标和、474.一和零
LeetCode1049
2025-03-04 18:48:44 星期二
题目描述:力扣1049
文档讲解:代码随想录(programmercarl)1049.最后一块石头的重量II
视频讲解:《代码随想录》算法视频公开课:这个背包最多能装多少?LeetCode:1049.最后一块石头的重量II
代码随想录视频内容简记

这道题目乍一看示例给的这个解题思路会觉得这怎么组合?没有一点头绪,后来看了k哥视频里讲的,这个题和416分割等和子集是差不多的,既然要求两块石头两两粉碎之后的差,那么其实可以转换为能不能定义一个sum/2,来让这些石头的重量相加等于这个数值。那么两堆石头重量的差就自然是0了
也就是压根不用找两两组合,应该用动态规划,这样的题目设置还是蛮巧妙的
梳理
-
确定dp[j]数组的含义,dp[j]就表示当背包容量为j时,所能放的物品的最大价值为dpj
-
确定递推公式,
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
-
dp数组初始化,下标为0初始化为0,非零下标也初始化为0即可,因为不能太大了
-
确定遍历顺序,先遍历物品,后遍历重量,重量记得是后序遍历
-
打印dp数组
LeetCode测试
需要注意的就是最后的返回值,因为一堆石头是dp[target],另一堆就是sum - dp[target]了,之后两堆再做差
点击查看代码
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int n = stones.size();
int sum = 0;
for (int i = 0; i < stones.size(); i++) {
sum += stones[i];
}
int target = sum / 2;
cout << sum << endl;
cout << target << endl;
vector<int> dp(target + 1, 0);
for (int i = 0; i < n; i++) {
for (int j = target; j >= 0; j--) {
if (j < stones[i]) dp[j] = dp[j];
else dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
cout << dp[target] << endl;
return sum - dp[target] - dp[target];
}
};
LeetCode494
题目描述:力扣494
文档讲解:代码随想录(programmercarl)494.目标和
视频讲解:《代码随想录》算法视频公开课:装满背包有多少种方法?| LeetCode:494.目标和
代码随想录视频内容简记
这道题要求的和之前的不太一样,本题求的是装满背包有多少种方法,不是之前的能不能装满或者装的最大价值是多少。
核心区别体现在递推公式发生了变化
要点
首先将题目抽象为01背包问题,要得到背包容量是多少。在本题中分正负两种数,那么我们只需要选择其中一种的正数作为背包容量进行“装填”即可
首先集合里需要为正数的left,需要为负数的right(加正负号之前)
那么将right代入得到:
举个例子,题目中给出的target=3, sum=5
,那么得到的背包容量应该是4。这里有个问题,就是一旦不能整除会怎么样?
如果target = 2,那么我们得到left = 3,那么right = 2,事实上二者做差并不能凑成2。所以一旦出现除不尽的情况,那么我们就直接返回0即可,0种方法
动归五部曲分析
-
确定dp[j]数组的含义,这里表示的是容量为j的背包装满有dp[j]种不同的方法
-
确定递推公式。这个确定多少种装满的方法的递推公式比较重要。首先是dp[j - nums[i]]的含义,这里就表示我们已有一个nums[i]重量的物品,剩余的空间放满有dp[j - nums[i]]种不同的方式。
举个例子:
nums[i] = 4,有dp[1]种不同的方式放满
nums[i] = 3,有dp[2]种不同的方式放满
nums[i] = 2,有dp[3]种不同的方式放满
nums[i] = 1,有dp[4]种不同的方式放满
nums[i] = 0,有dp[5]种不同的方式放满
注:这里可以参考之前70爬楼梯的思想
所以dp[5]装满的不同方式就是有dp[4]+dp[3]+dp[2]+dp[1]+dp[0]
种不同的方式
也就是递推公式为:dp[j] += dp[j - nums[i]]
-
dp数组初始化,要进行初始化,dp[0]需要设置为多少呢?其实正常的理解这里应该是0没有问题,但是我们可以测试一下。
如果dp[0]是0,那么dp[1] = dp[1 - 1] = dp[0]也是0,dp[2] = dp[1] + dp[0]也是0,所以后面就全是0了。故,不能初始化为0。
这里dp[0]初始化为1即可,虽然从定义上并不说得通,但是可以当成一种特值,不必太过纠结。
至于非零下标,仍让初始化为0即可。 -
遍历顺序,仍然是先遍历物品,后便利重量
-
打印dp数组
LeetCode测试
这里有个小细节,就是会有的测试用例算出来left是负数的情况,这样的话建立数组就会出问题了,需要额外加一个判断,if (left < 0) return 0
点击查看代码
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
}
if ((sum + target) % 2 == 1) return 0;
int left = (sum + target) / 2;
if (left < 0) return 0;
int right = sum - left;
// cout << left;
vector<int> dp(left + 1, 0);
dp[0] = 1;
for (int i = 0; i < nums.size(); i++) {
for (int j = left; j >= 0; j--) {
if (j < nums[i]) dp[j] = dp[j];
else dp[j] += dp[j - nums[i]];
}
}
return dp[left];
}
};
LeetCode474
题目描述:力扣474
文档讲解:代码随想录(programmercarl)474.一和零
视频讲解:《代码随想录》算法视频公开课:装满这个背包最多用多少个物品?| LeetCode:474.一和零
代码随想录视频内容简记
这道题目可以抽象为:集合种每一个字符串堪称一个物品,其有两个维度的指标:分别是0的个数和1的个数,那么本题要求的就是在满足0和1个数的情况下,使物品的个数最大
这道题目的每个字符串的0和1的个数可以抽象成01背包的重量,只不过特殊的地方在于重量是两个维度,所以按照之前的一维dp[j],在这里会变成一个dp[i][j]
梳理
-
确定dp[i][j]数组的定义,表示背包中有i个0和j个1时最多的物品个数
-
确定递推公式。这里用
dp[i][j] = max(dp[i][j], dp[i - x][j - y] + 1)
。解释一下dp[i - x][j - y] + 1
的含义,这里的x和y表示的就是子字符串的01个数,其表示重量,而value在本题中表示为物品的个数,也就是子字符串的个数,一次只能加1,所以后面就是+1 -
初始化dp[i][j]数组。dp[0][0]表示要求0和1的个数最多不能超多0个,所以直接为0即可,至于非零下标,仍然表示为最小的非零数即可
-
确定遍历顺序,仍旧是先遍历物品,后遍历重量,重量从后向前
-
打印dp数组
LeetCode测试
for (char c : str) {
if (c == '0') x++;
if (c == '1') y++;
}
还有就是注意这里的写法
点击查看代码
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
for (string str : strs) {// 遍历物品
int x = 0, y = 0;
for (char c : str) {
if (c == '0') x++;
if (c == '1') y++;
}
for (int i = m ; i >= 0; i--) { // 遍历重量
for (int j = n; j >= 0; j--) {
if (i < x || j < y) dp[i][j] = dp[i][j];
else dp[i][j] = max(dp[i][j], dp[i - x][j - y] + 1);
}
}
}
return dp[m][n];
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端