LeetCode刷题 Day43

81 阅读3分钟

LeetCode刷题 Day43

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.

Example 1:

Input: nums = [1,1,1,1,1], target = 3
Output: 5
Explanation: There are 5 ways to assign symbols to make the sum of nums be target 3.
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

Example 2:

Input: nums = [1], target = 1
Output: 1

思路: 难点在于如何把它转化成背包问题, left - right = target left + right = Sum

left = (target + Sum) / 2

这样就是要找出和为left的值, left为背包容量

步骤:

  1. dp的index和value: index为背包容量,value为该容量下放入物品的组合数
  2. 递推公式: dp[j] += dp[j - nums[i]], 意思是凑成dp[j]可以有dp[j - nums[i]]种组合数 dp[j],j 为5,
  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 dp[5]。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 dp[5]。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 dp[5]
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 dp[5]
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 dp[5]
  1. 初始化: dp[0] 为1, 装满容量为0的背包的一种方法就是放入0件物品
  2. 遍历顺序: 一维背包,物品外循环正向,背包内循环逆向
  3. 举例论证:

image.png

代码:

var findTargetSumWays = function(nums, target) {
    let numSum  = nums.reduce((a, b) => a + b);
    if (target > numSum) return 0;
    if ((target + numSum) % 2 === 1) return 0;

    let targetVal = (target + numSum) / 2;

    if (targetVal < 0) return 0;
    
    let dp = Array(targetVal + 1).fill(0);
    dp[0] = 1;
    
    for (let num of nums) {
        for (let j = targetVal; j >= num; j--) {
            dp[j] += dp[j - num];
        }
    }
    
    return dp[targetVal];
};

时间复杂度: O(n2), 空间复杂度: O(n)


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.

Example 1:

Input: stones = [2,7,4,1,8,1]
Output: 1
Explanation:
We can combine 2 and 4 to get 2, so the array converts to [2,7,1,8,1] then,
we can combine 7 and 8 to get 1, so the array converts to [2,1,1,1] then,
we can combine 2 and 1 to get 1, so the array converts to [1,1,1] then,
we can combine 1 and 1 to get 0, so the array converts to [1], then that's the optimal value.

Example 2:

Input: stones = [31,26,33,21,40]
Output: 5

思路: 根据题意,这道题也是求sum/2, 把sum/2作为一个target。

步骤:

  1. dp的inde和value. index表示背包容量。value为这个背包下装入物品重量
  2. dp推导公式: dp[j] = Math.max(dp[j], dp[j - stone] + stone);
  3. 初始化: dp[0] = 0,容量为0的时候,重量为0
  4. 遍历顺序: 一维背包的遍历顺序, 物品在外面循环正序,背包在内循环逆序
  5. 举例论证:

image.png

var lastStoneWeightII = function(stones) {
    // get target
    let sum = stones.reduce((a, b) => a + b);
    let target = Math.floor(sum / 2);
    let dp = Array(target + 1).fill(0);

    for (let stone of stones) {
        for (let j = target; j >= stone; j--) {
            dp[j] = Math.max(dp[j], dp[j - stone] + stone);
        }
    }
    return sum - dp[target] - dp[target];
};

时间复杂度: O(n2) 空间复杂度: O(n)


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.

Example 1:

Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3
Output: 4
Explanation: The largest subset with at most 5 0's and 3 1's is {"10", "0001", "1", "0"}, so the answer is 4.
Other valid but smaller subsets include {"0001", "1"} and {"10", "1", "0"}.
{"111001"} is an invalid subset because it contains 4 1's, greater than the maximum of 3.

Example 2:

Input: strs = ["10","0","1"], m = 1, n = 1
Output: 2
Explanation: The largest subset is {"0", "1"}, so the answer is 2.

思路: 这也是一个01背包的问题,背包的容量是二维的,一个是0的个数:m,一个是1的个数: n。 在循环内部首先计算每个str的0的个数和1的个数,然后通过 dp[m - zeroNum][n - oneNum] + 1传递

步骤:

  1. dp index和value的意义: index代表背包容量,value代表subset数量
  2. 递推公式: dp[m - zeroNum][n - oneNum] + 1
  3. 初始化: dp[0][0] = 0, 0容量0 subset
  4. 遍历顺序,这个是一个多重循环,因为有两个维度
  5. 举例论证:

image.png

代码:

var findMaxForm = function(strs, m, n) {
    let dp = []
    for (let i = 0; i <= m; i++) {
        dp.push(Array(n + 1).fill(0));
    }

    for (let str of strs) {
        let zeroNum = 0;
        let oneNum = 0;

        for (let cIndex = 0; cIndex <str.length; cIndex++) {
            if (str[cIndex] ===  '0') zeroNum++;
            else oneNum++;
        }

        for (let i = m; i >= zeroNum; i--) {
            for (let j = n; j >= oneNum; j--) {
                dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
            }
        }
    }

    return dp[m][n];
};

时间复杂度: O(m * n * strs.length)