474. 一和零
给你一个二进制字符串数组
strs
和两个整数m
和n
。请你找出并返回
strs
的最大子集的长度,该子集中 最多 有m
个0
和n
个1
。如果
x
的所有元素也是y
的元素,集合x
是集合y
的 子集 。示例 1:
输入: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 。示例 2:
输入:strs = ["10", "0", "1"], m = 1, n = 1 输出:2 解释:最大的子集是 {"0", "1"} ,所以答案是 2 。提示:
1 <= strs.length <= 600
1 <= strs[i].length <= 100
strs[i]
仅由'0'
和'1'
组成1 <= m, n <= 100
状态:没写出来
思路:这是一个背包容量是二维的0-1背包问题,因为每个物品只能取一次。背包容量是二维的所以dp数组也是二维的,但遍历方式是跟背包容量一维时的一维数组方式一致从前向后因为不能重复的取值。dp[k][j]表示当有k个0j个1时有多少个元素数组中,状态转移方程是
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp=new int[m+1][n+1];
for(String str:strs){
int x=0;
int y=0;
for(char a:str.toCharArray()){
if(a=='0') x++;
else y++;
}
for(int k=m;k>=x;k--){
for(int j=n;j>=y;j--){
dp[k][j]=Math.max(dp[k-x][j-y]+1,dp[k][j]);
}
}
}
return dp[m][n];
}
}
完全背包
完全背包跟0-1背包的区别就是物品的取值能否重复取,其他都基本一致。
因为可以重复取值所以dp[i][j]在本一行中去对比dp[i][j]的值就可以了,所以状态转移方程为
下面的代码就是最基础的完全背包问题:
import java.util.*;
public class Main{
public static void main (String[] args) {
/* code */
Scanner sc=new Scanner(System.in);
int N=sc.nextInt();
int V=sc.nextInt();
int[] weights=new int[N];
int[] values=new int[N];
for(int i=0;i<N;i++){
weights[i]=sc.nextInt();
values[i]=sc.nextInt();
}
int[][] dp=new int[N][V+1];
for(int i=1;i<=V;i++){
if(weights[0]<i)
dp[0][i]=(i/weights[0])*values[0];
}
for(int i=1;i<N;i++){
for(int j=0;j<=V;j++){
if(j<weights[i]){
dp[i][j]=dp[i-1][j];
continue;
}
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-weights[i]]+values[i]);
}
}
System.out.println(dp[N-1][V]);
}
}
518. 零钱兑换 II
给你一个整数数组
coins
表示不同面额的硬币,另给一个整数amount
表示总金额。请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回
0
。假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
示例 1:
输入:amount = 5, coins = [1, 2, 5] 输出:4 解释:有四种方式可以凑成总金额: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1示例 2:
输入:amount = 3, coins = [2] 输出:0 解释:只用面额 2 的硬币不能凑成总金额 3 。示例 3:
输入:amount = 10, coins = [10] 输出:1提示:
1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins
中的所有值 互不相同0 <= amount <= 5000
状态:完成,wa了一次,因为没有把[0,0]置1
思路:这题跟之前那个求最多的方法的0-1背包问题差不多,就是可以取得物品变成了无限个,变一下状态转移方程即可。不过要记得把背包容量是0的时候置1.
class Solution {
public int change(int amount, int[] coins) {
int[][] dp=new int[coins.length][amount+1];
for(int i=1;i<=amount;i++){
dp[0][i]=i%coins[0]==0?1:0;
}
for(int i=0;i<coins.length;i++){
dp[i][0]=1;
}
for(int i=1;i<coins.length;i++){
for(int j=1;j<=amount;j++){
if(j<coins[i]){
dp[i][j]=dp[i-1][j];
continue;
}
dp[i][j]=dp[i-1][j]+dp[i][j-coins[i]];
}
}
return dp[coins.length-1][amount];
}
}
感想:前几天去打泰迪杯搞得没刷这两天,现在补回来,继续进步。今天完全背包还是很好理解的。