1 推荐刷题集合
2 lc 416. 分割等和子集
public boolean canPartition(int[] nums) {
int n=nums.length;
int s=0;
for(int i=0;i<n;i++){
s+=nums[i];
}
if(s%2==1){
return false;
}
boolean[]f=new boolean[s/2+1];
f[0]=true;
for(int i=0;i<n;i++){
for(int j=s/2;j>=nums[i];j--){
f[j]=f[j]||f[j-nums[i]];
}
}
return f[s/2];
}
3 LC494. 目标和
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int n=nums.length;
int s=Arrays.stream(nums).sum();
int diff=s-target;
if(diff<0||diff%2==1)return 0;
int t=diff/2;
int[]f=new int[t+1];
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=t;j>=nums[i-1];j--){
f[j]+=f[j-nums[i-1]];
}
}
return f[t];
}
public int findTargetSumWays2(int[] nums, int target) {
int n=nums.length;
int s=Arrays.stream(nums).sum();
int diff=s-target;
if(diff<0||diff%2==1)return 0;
int t=diff/2;
// f[i][j]:当从前i个数中做选择时,
int[][]f=new int[n+1][t+1];
f[0][0]=1;
for(int i=1;i<=n;i++){
// for(int j=t;j>=nums[i-1];j--){
for(int j=0;j<=t;j++){
f[i][j]=f[i-1][j];
if(j>=nums[i-1])
f[i][j]+=f[i-1][j-nums[i-1]];
}
}
return f[n][t];
}
}
4 LC474. 一和零
4.1 描述
4.2 答案
https://leetcode.cn/problems/ones-and-zeroes/solutions/814806/yi-he-ling-by-leetcode-solution-u2z2/
4.3 改编为“恰好0-1背包问题”这个是0-1背包问题,如果我改一下,将“该子集中 最多 有 m 个 0 和 n 个 1 。”改为恰好有m 个 0 和 n 个 1",这个题java怎么解?
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
// 初始化,除了dp[0][0],其他都是最小值,因为我们需要恰好填满背包
for (int i = 0; i <= m; i++) {
Arrays.fill(dp[i], Integer.MIN_VALUE);
}
dp[0][0] = 0;
for (String s : strs) {
int[] count = countZerosOnes(s);
int zeros = count[0];
int ones = count[1];
// 必须倒序遍历,因为每个字符串只能用一次
for (int i = m; i >= zeros; i--) {
for (int j = n; j >= ones; j--) {
if (dp[i - zeros][j - ones] != Integer.MIN_VALUE) {
dp[i][j] = Math.max(dp[i][j], dp[i - zeros][j - ones] + 1);
}
}
}
}
// 找到恰好为m个0和n个1的最大子集长度
return dp[m][n] == Integer.MIN_VALUE ? 0 : dp[m][n];
}
private int[] countZerosOnes(String str) {
int[] count = new int[2];
for (char c : str.toCharArray()) {
count[c - '0']++;
}
return count;
}