细数Leetcode上的背包问题

1 推荐刷题集合

细数Leetcode上的背包问题_第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 描述

细数Leetcode上的背包问题_第2张图片

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;
}

你可能感兴趣的:(算法,java,数据结构,背包问题)