第九章 动态规划 part05

52 阅读1分钟

1049. Last Stone Weight II

You are given an array of integers stones where stones[i] is the weight of the ith stone.

We are playing a game with the stones. On each turn, we choose any two stones and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is:

  • If x == y, both stones are destroyed, and
  • If x != y, the stone of weight x is destroyed, and the stone of weight y has new weight y - x.

At the end of the game, there is at most one stone left.

Return the smallest possible weight of the left stone. If there are no stones left, return 0.

题目解析:

  • 尽量把石头分成重量均匀的两堆,这样最后碰撞剩余的重量最小。所以问题转化为容量为总重量一般的背包最多能装多少石头

代码:

class Solution {
    public int lastStoneWeightII(int[] stones) {
        if (stones.length == 1) return stones[0];
        int sum = Arrays.stream(stones).sum();
        int half = sum / 2;
        int[] dp = new int[half+1];
        dp[0] = 0;
        for (int stone: stones) {
            for (int i = half; i > 0; i--) {
                if (i-stone >= 0) {
                    dp[i] = Math.max(dp[i], dp[i-stone] + stone);
                }
            }
        }
        return sum - dp[half] - dp[half];
    }
}

494. Target Sum

You are given an integer array nums and an integer target.

You want to build an expression out of nums by adding one of the symbols '+' and '-' before each integer in nums and then concatenate all the integers.

  • For example, if nums = [2, 1], you can add a '+' before 2 and a '-' before 1 and concatenate them to build the expression "+2-1".

Return the number of different expressions that you can build, which evaluates to target.

题目解析:

  • 类似的思路,把数组分为两堆,一堆全为+, 另一堆全为-, 这样两堆之和为sum,两堆之差就为target
  • left + right = sum; left - right = target => left = (sum +target) / 2

代码:

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        // + : left,  - : right
        // left + right = sum; left - right = target => left = (sum +target) / 2
        int sum = Arrays.stream(nums).sum();
        if (sum + target < 0 || (sum + target) % 2 != 0) return 0;
        int left = (sum + target) / 2;
        int[] dp = new int[left+1];
        dp[0] = 1;
        for (int num : nums) {
            for (int i = left; i >= num; i--) {
                dp[i] += dp[i-num];
            }
        }
        return dp[left];
    }
}

474. Ones and Zeroes

You are given an array of binary strings strs and two integers m and n.

Return the size of the largest subset of strs such that there are at most m **0 's and n **1 's in the subset.

A set x is a subset of a set y if all elements of x are also elements of y.

题目解析:

  • 两个维度的01背包

代码:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        for (int k = 0; k < strs.length; k++) {
            int one = 0, zero = 0;
            for (int i = 0; i < strs[k].length(); i++) {
                if (strs[k].charAt(i) == '0') zero++;
                if (strs[k].charAt(i) == '1') 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];
    }
}

总结

  • 01背包从后往前遍历