代码随想录训练营二刷第四十五天 | 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

代码随想录训练营二刷第四十五天 | 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

一、1049. 最后一块石头的重量 I

题目链接:https://leetcode.cn/problems/last-stone-weight-ii/
思路:两两抵消求最后一块石头的重量,即尽可能的把石头分成两堆,即总数和的一半,最后用总数和的一半作为容量,得到最大能存放的重量,总重量减去两倍的该重量即为抵消之后的重量。

class Solution {
   public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for(int i : stones) {
            sum += i;
        }
        int temp = sum;
        sum /= 2;
        int[] dp = new int[sum+1];
        for (int i = 0; i < stones.length; i++) {
            for (int j = sum; j >= stones[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j-stones[i]] + stones[i]);
            }
            if (dp[sum] == sum) break;
        }
        return temp - 2 * dp[sum];
    }
}

二、1494. 目标和

题目链接:https://leetcode.cn/problems/target-sum/
思路:求目标和即为 x - y = target, x + y = sum。我们只需要计算背包容量为x把他填满有多少种方法即可。
如果abs(target > sum) 无解,(target + sum) % 2 != 0 无解,因为target + sum= 2*x,这个整除2一定等于0,不等于0说明target有问题无解。
定义dp[j]表示容量为j时有多少种组合。
dp[j] += dp[j - nums[i]]。
例如:dp[j],j 为5,

已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 容量为5的背包。
已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 容量为5的背包。
已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 容量为5的背包
已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 容量为5的背包
已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 容量为5的背包
初始化dp[0]=1;
一维数组遍历顺序依然是先物品,后背包,背包逆序。

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
        }
        if (Math.abs(target) > sum) return 0;
        if ((target + sum) % 2 != 0) return 0;
        int left = (target + sum) / 2;
        int[] dp = new int[left + 1];
        dp[0] = 1;
        for (int i = 0; i < nums.length; i++) {
            for (int j = left; j >= nums[i]; j--) {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[left];
    }
}

三、1 474.一和零

题目链接:https://leetcode.cn/problems/ones-and-zeroes/
思路:一和零实际上是一个二维背包问题。每一个元素是一个字符串,这个字符串有两个指标,一个是0一个是1。
定义dp[i][j]表示,当0的数量为i,1的数量为j时,背包中存放的字符串个数为dp[i][j]个。
递推公式:dp[i][j] = Math.max(dp[i][j], dp[i-zero][j-one] + 1);
当前字符串不放入其中,为dp[i][j]即没覆盖之前的值,也就是之前的字符串途经此处得到的最大值。
放入其中,即为背包0为i-zero,1为j-one时背包中存放的最大字符串个数加上当前的这一个字符串。dp[i-zero][j-one] + 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 zero = 0, one = 0;
            for (char ch : str.toCharArray()) {
                if (ch == '0') zero++;
                else one++;
            }
            for (int i = m; i >= zero; i--) {
                for (int j = n; j >= one; j--) {
                    dp[i][j] = Math.max(dp[i][j], dp[i-zero][j-one] + 1);
                }
            }
        }
        return dp[m][n];
    }
}

你可能感兴趣的:(力扣算法题,算法,数据结构,动态规划)