01背包:
416.分割等和子集
494.目标和
完全背包:
322.零钱兑换
518.零钱兑换II
377.组合总和IV
139.单词拆分
01背包问题:每个元素只能使用一次。
416.分割等和子集
//使用二维dp数组
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
if(len == 0) {
return false;
}
int sum = 0;
for(int i = 0; i < len; i++) {
sum += nums[i];
}
if((sum&1) == 1) {//根据题意,sum必须是偶数
return false;
}
int verge = sum/2;//最大背包的体积
boolean[][] dp = new boolean[len][verge+1];//前i个物品能放入背包中
//初始化
dp[0][0] = true;
if(nums[0] <= verge) {//至少第一个物体能放入吧
dp[0][nums[0]] = true;
}
//开始填表
for(int i = 1; i < len; i++) {
for(int j = 0; j <= verge; j++) {
dp[i][j] = dp[i-1][j];//上一个背包都装不下,换大物件当然也装不下
if(nums[i] == j) {//正好容量等于背包容量的话
dp[i][j] = true;
continue;
}
if(nums[i] < j) {//小于背包容量
//选择放或者不放,如果不放的话,表格的上一个也要为真;如果放的话,j-nums[i]表示能够放下
dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]];
}
}
}
return dp[len-1][verge];//最大容量时能否装满呢
}
}
//使用一维数组
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
if(len == 0) {
return false;
}
int sum = 0;
for(int i = 0; i < len; i++) {
sum += nums[i];
}
if((sum&1) == 1) {//根据题意,sum必须是偶数
return false;
}
int verge = sum/2;//最大背包的体积
boolean[] dp = new boolean[verge+1];
dp[0] = true;
for(int i = 1; i < len; i++) {
for(int j = verge; nums[i] <= j; j--) {//必须使用倒序,因为dp[j]要由dp[j-nums[i]]推出
if(dp[verge]) {
return true;
}
dp[j] = dp[j] || dp[j-nums[i]];
}
}
return dp[verge];
}
}
class Solution {
public int findTargetSumWays(int[] nums, int S) {
int len = nums.length;
int sum = 0;
for (int i : nums) {
sum += i;
}
if(sum < S) return 0;
sum = sum + S;
if(sum%2 == 1) {
return 0;
}
sum = sum/2;
int[] dp = new int[sum+1];
dp[0] = 1;
for(int i = 0; i < len; i++) {
for(int j = sum; j >= nums[i]; j--) {
if(dp[j-nums[i]] > 0) {
dp[j] += dp[j-nums[i]];
}
}
}
return dp[sum];
}
}
完全背包:物品有取0件,取1件,取2件…等多种。
322.零钱兑换
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];//最小硬币数
Arrays.fill(dp, 1,amount+1, amount+1);
for(int i = 0; i < coins.length; i++) {
for(int j = coins[i]; j <= amount; j++) {
if(dp[j-coins[i]] != amount+1) {//如果依然等于amount+1,说明没有硬币可以凑出这个值;
dp[j] = Math.min(dp[j], dp[j-coins[i]] + 1);
}
}
}
return dp[amount] == amount+1 ? -1 : dp[amount];
}
}
class Solution {
public int change(int amount, int[] coins) {
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++) {
if(j >= coins[i]) {
dp[j] += dp[j-coins[i]];
}
}
}
return dp[amount];
}
}
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target+1];
dp[0] = 1;
for(int i = 1; i <= target; i++) {
for(int j = 0; j < nums.length; j++) {
if(i >= nums[j] && dp[i-nums[j]] > 0) {
dp[i] += dp[i-nums[j]];
}
}
}
return dp[target];
}
}
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int len = s.length();
boolean[] dp = new boolean[len+1];
dp[0] = true;
for(int i = 1; i <= len; i++) {
for(int j = 0; j < wordDict.size(); j++) {
String word = wordDict.get(j);
int lenth = word.length();
if(i >= lenth && dp[i-lenth]) {
String ss = s.substring(i-lenth, i);
if(ss.equals(word)) {
dp[i] = true;
}
}
}
}
return dp[len];
}
}