1049. 最后一块石头的重量 Ⅱ
题目:1049. 最后一块石头的重量 II - 力扣(LeetCode)
题解:代码随想录 (programmercarl.com)
背包问题的难点:看不出为啥是背包问题。。。
solution
public class Solution {
public int LastStoneWeightII(int[] stones) {
int totalWeight = 0;
foreach (int stone in stones)
{
totalWeight += stone;
}
int halfWeight = totalWeight / 2;
bool[] dp = new bool[halfWeight + 1];
dp[0] = true;
foreach (int stone in stones)
{
for (int j = halfWeight; j >= stone; j--)
{
dp[j] = dp[j] || dp[j - stone];
}
}
for (int j = halfWeight; j >= 0; j--)
{
if (dp[j])
{
return totalWeight - 2 * j;
}
}
return 0; // 虽然实际情况中不可能到达这里
}
}
summary
1、问题转化:
使两个组的重量差最小 ---> 选择一些石头使得其总重量尽可能接近总重量的一半。
设总重量为 totalWeight,那么每组的目标是 totalWeight / 2。需要找到一个子集,使得其重量尽可能接近 totalWeight / 2。
2、dp
dp[j] :是否存在一个子集,其总重量为 j
初始化 dp[0] = true
494. 目标和
题目:494. 目标和 - 力扣(LeetCode)
题解:代码随想录 (programmercarl.com)
这题好想一点!
综合上一题看出dp题目的突破口还在递推公式,递推公式的突破口在找到前后元素的关系
发现dp的题使用图解法有奇效
solution
public class Solution {
public int FindTargetSumWays(int[] nums, int target) {
int sum = nums.Sum();
if(target > sum || target < -sum) return 0;
int[,] dp = new int[nums.Length, 2*sum + 1];
for(int i = 0; i < nums.Length; i ++)
{
for(int j = 0; j <= 2*sum; j ++)
{
if(i == 0)
dp[0, j] = (nums[i] == j - sum ? 1 : 0) + (-nums[i] == j - sum ? 1 : 0);
else
dp[i, j] = (j - nums[i] >= 0 ? dp[i - 1, j - nums[i]] : 0) + (j + nums[i] <= 2*sum ? dp[ i - 1, j + nums[i]] : 0);
}
}
return dp[nums.Length - 1, sum + target];
}
}
summary
我真的恨0
474. 一和零
solution
public class Solution {
public int FindMaxForm(string[] strs, int m, int n) {
// 创建一个二维数组 dp,大小为 (m + 1) x (n + 1)
int[,] dp = new int[m + 1, n + 1];
// 遍历所有字符串
foreach (string str in strs)
{
int zeroCount = 0;
int oneCount = 0;
// 计算当前字符串中的 '0' 和 '1' 的数量
foreach (char c in str)
{
if (c == '0') zeroCount++;
if (c == '1') oneCount++;
}
// 从背包的最大容量开始倒序更新 dp 数组
for (int i = m; i >= zeroCount; i--)
{
for (int j = n; j >= oneCount; j--)
{
// 选择放入当前字符串或不放入当前字符串
dp[i, j] = Math.Max(dp[i, j], dp[i - zeroCount, j - oneCount] + 1);
}
}
}
// 返回使用最多 m 个 '0' 和 n 个 '1' 时可以获得的最大字符串数量
return dp[m, n];
}
}