4.13 完全背包

This commit is contained in:
zhangsan 2025-04-13 14:09:25 +08:00
parent a7d420dc78
commit 4ea0dcfb2d
6 changed files with 210 additions and 0 deletions

View File

@ -0,0 +1,32 @@
package dynamic_programming;
/**
* 题目 518. 零钱兑换 II (change)
* 描述给你一个整数数组 coins 表示不同面额的硬币另给一个整数 amount 表示总金额
* 请你计算并返回可以凑成总金额的硬币组合数如果任何硬币组合都无法凑出总金额返回 0
* 假设每一种面额的硬币有无限个
* 题目数据保证结果符合 32 位带符号整数
示例 2
输入amount = 5, coins = [1, 2, 5]
输出4
解释有四种方式可以凑成总金额
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
* 链接https://leetcode.cn/problems/coin-change-ii/
*/
public class Change {
public int change(int amount, int[] coins) {
int[]dp=new int[amount+1];
dp[0]=1;
for (int coin : coins) {
for (int j = 0; j <= amount; j++) {
if (j - coin >= 0)
dp[j] += dp[j - coin];
}
}
return dp[amount];
}
}

View File

@ -0,0 +1,35 @@
package dynamic_programming;
/**
* 题目 377. 组合总和 (CombinationSum4 )
* 描述给你一个由 不同 整数组成的数组 nums 和一个目标整数 target 请你从 nums 中找出并返回总和为 target 的元素组合的个数
* 题目数据保证答案符合 32 位整数范围
示例 2
输入nums = [1,2,3], target = 4
输出7
解释
所有可能的组合为
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意顺序不同的序列被视作不同的组合
* 链接https://leetcode.cn/problems/combination-sum-iv/
*/
public class CombinationSum4 {
public int combinationSum4(int[] nums, int target) {
int[]dp=new int[target+1];
dp[0]=1;
for (int j = 0; j <= target; j++) {
for (int num : nums) {
if(j-num>=0)
dp[j] += dp[j - num];
}
}
return dp[target];
}
}

View File

@ -0,0 +1,38 @@
package dynamic_programming;
/**
* 题目 474. 一和零 (FindMaxForm)
* 描述给你一个二进制字符串数组 strs 和两个整数 m n
* 请你找出并返回 strs 的最大子集的长度该子集中 最多 m 0 n 1
* 如果 x 的所有元素也是 y 的元素集合 x 是集合 y 子集
示例 2
输入strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出4
解释最多有 5 0 3 1 的最大子集是 {"10","0001","1","0"} 因此答案是 4
其他满足题意但较小的子集包括 {"0001","1"} {"10","1","0"} {"111001"} 不满足题意因为它含 4 1 大于 n 的值 3
* 链接https://leetcode.cn/problems/ones-and-zeroes/
*/
public class FindMaxForm {
int[] cnt(String str){
int cntzero=0,cntone=0;
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i)=='0')
cntzero++;
else cntone++;
}
return new int[]{cntzero,cntone};
}
public int findMaxForm(String[] strs, int m, int n) {
int[][]dp=new int[m+1][n+1]; //最多m个0 n个1,能选取的字符串的个数 而不是组合数
for (String str : strs) {
int[] res = cnt(str);
for (int j = m; j >= res[0]; j--) {
for (int k = n; k >= res[1]; k--) {
dp[j][k] =Math.max(dp[j][k],dp[j - res[0]][k - res[1]]+1);
}
}
}
return dp[m][n];
}
}

View File

@ -0,0 +1,50 @@
package dynamic_programming;
/**
* 题目 494. 目标和 (FindTargetSumWays)
* 描述给你一个非负整数数组 nums 和一个整数 target
* 向数组中的每个整数前添加 '+' '-' 然后串联起所有整数可以构造一个 表达式
* 例如nums = [2, 1] 可以在 2 之前添加 '+' 1 之前添加 '-' 然后串联起来得到表达式 "+2-1"
* 返回可以通过上述方法构造的运算结果等于 target 的不同 表达式 的数目
示例 2
输入nums = [1,1,1,1,1], target = 3
输出5
解释一共有 5 种方法让最终目标和为 3
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
* 链接https://leetcode.cn/problems/target-sum/
*/
public class FindTargetSumWays {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int num : nums) {
sum += num;
}
// 如果 (sum + target) 不是偶数或者 target 超出 sum 的范围说明无解
if ((sum + target) % 2 != 0 || Math.abs(target) > sum) {
return 0;
}
// 目标正集合和 P
int P = (sum + target) / 2;
// dp[j] 表示选取若干数凑出和 j 的方案数
int[] dp = new int[P + 1];
dp[0] = 1; // 凑出 0 的和只有一种方案不选任何数
// 遍历每个数字
for (int num : nums) {
// 逆序遍历确保每个数字只被使用一次
for (int j = P; j >= num; j--) {
dp[j] += dp[j - num];
}
}
return dp[P];
}
}

View File

@ -0,0 +1,39 @@
package dynamic_programming;
import java.util.Arrays;
/**
* 题目 1049. 最后一块石头的重量 II (lastStoneWeightII)
* 描述有一堆石头用整数数组 stones 表示其中 stones[i] 表示第 i 块石头的重量
* 每一回合从中选出任意两块石头然后将它们一起粉碎假设石头的重量分别为 x y x <= y那么粉碎的可能结果如下
* 如果 x == y那么两块石头都会被完全粉碎
* 如果 x != y那么重量为 x 的石头将会完全粉碎而重量为 y 的石头新重量为 y-x
* 最后最多只会剩下一块 石头返回此石头 最小的可能重量 如果没有石头剩下就返回 0
示例 2
输入stones = [2,7,4,1,8,1]
输出1
解释
组合 2 4得到 2所以数组转化为 [2,7,1,8,1]
组合 7 8得到 1所以数组转化为 [2,1,1,1]
组合 2 1得到 1所以数组转化为 [1,1,1]
组合 1 1得到 0所以数组转化为 [1]这就是最优值
* 链接https://leetcode.cn/problems/last-stone-weight-ii/
*/
public class LastStoneWeightII {
public int lastStoneWeightII(int[] stones) {
int sum=0;
for (int stone : stones) {
sum+=stone;
}
int half=sum/2;
int[] dp=new int[half+1];
for (int stone : stones) {
for (int j = half; j >= stone; j--) {
dp[j] = Integer.max(dp[j], dp[j - stone] + stone);
}
}
return Math.abs(sum-2*dp[half]);
}
}

View File

@ -0,0 +1,16 @@
package dynamic_programming;
import org.junit.Test;
import static org.junit.Assert.*;
public class LastStoneWeightIITest {
@Test
public void lastStoneWeightII() {
LastStoneWeightII solution = new LastStoneWeightII();
int[]stones = {2,7,4,1,8,1};
int res=solution.lastStoneWeightII(stones);
System.out.println(res);
}
}