动态规划步骤
确认dp数组含义,求递推公式,进行dp数组初始化,遍历顺序,打印
01背包问题,每件物品只有一样,我们的选择是拿或者不拿;于完全背包问题,每件物品有无数个,同样求解将哪些物品放入背包中,可以使得背包放入物品的总价值最大:
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
根据数组的长度 nn 判断数组是否可以被划分。如果 n<2,则不可能将数组分割成元素和相等的两个子集,因此直接返回 false。计算整个数组的元素和sum如果 sum 是奇数,则不可能将数组分割成元素和相等的两个子集,因此直接返回 false。如果sum 是偶数,则令 target= sum/2,需要判断是否可以从数组中选出一些数字,使得这些数字的和等于target。在这里nums数组中的每个值都相当于背包问题的重量和价值,如果最大价值等于target则就可以划分两个子集。
public boolean canPartition(int[] nums) { if(nums.length<2) return false; int sum = Arrays.stream(nums).sum(); if(sum%2!=0) return false; int target = sum / 2; int[][] dp=new int[nums.length+1][target+1]; for(int i=1;i<dp.length;i++){ for(int j=1;j<dp[0].length;j++){ if(nums[i-1]>j) dp[i][j]=dp[i-1][j]; else dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-nums[i-1]]+nums[i-1]); } } return dp[nums.length][target]==target; }
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
输入: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
引用官方图片
class Solution { public int findTargetSumWays(int[] nums, int target) { int sum = 0; for (int num : nums) { sum += num; } int diff = sum - target; if (diff < 0 || diff % 2 != 0) { return 0; } int n = nums.length, neg = diff / 2; int[][] dp = new int[n + 1][neg + 1]; dp[0][0] = 1; for (int i = 1; i <= n; i++) { int num = nums[i - 1]; for (int j = 0; j <= neg; j++) { dp[i][j] = dp[i - 1][j]; if (j >= num) { dp[i][j] += dp[i - 1][j - num]; } } } return dp[n][neg]; } }
完全背包
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
public int change(int amount, int[] coins) { int[][] dp=new int[coins.length+1][amount+1]; dp[0][0]=1; for (int i=1;i<dp.length;i++){ for(int j=0;j<dp[0].length;j++){ dp[i][j]=dp[i-1][j]; if(coins[i-1]<=j) dp[i][j]+=dp[i][j-coins[i-1]]; } } return dp[coins.length][amount]; }