0/1背包
416. 分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
public boolean canPartition(int[] nums) {int n = nums.length;int sum = 0;for (int num : nums) {sum += num;}int m = sum / 2;if (sum % 2 != 0) {return false;}// dp[i][j]表示在前i个元素中是否能选一些元素和为jboolean[][] dp = new boolean[n + 1][m + 1];dp[0][0] = true;for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {// 选该元素或者不选if (j >= nums[i - 1]) { // 选: i-1就已经满足了 或者加上i位置刚好等于jdp[i][j] = dp[i - 1][j - nums[i - 1]] || dp[i - 1][j];} else { // 不选dp[i][j] = dp[i - 1][j]; // 前i-1位置能否凑齐j}}}return dp[n][m];}
空间优化
public boolean canPartition(int[] nums) {int n = nums.length;int sum = 0;for (int num : nums) {sum += num;}int m = sum / 2;if (sum % 2 != 0) {return false;}// dp[i][j]表示在前i个元素中是否能选一些元素和为jboolean[] dp = new boolean[m + 1];dp[0] = true;for (int i = 1; i < n; i++) {for (int j = m; j >= nums[i]; j--) {// 选该元素或者不选dp[j] = dp[j] || dp[j - nums[i]];}}return dp[m];}
完全背包
518. 零钱兑换 II
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。
public int change(int amount, int[] coins) {// dp[n]表示凑齐n面额的方法数int[] dp = new int[amount + 1];dp[0] = 1;for (int i = 0; i < coins.length; i++) {for (int j = coins[i]; j <= amount; j++) {dp[j] += dp[j - coins[i]];}}return dp[amount];}

