代码随想录第43天|1049. 最后一块石头的重量 II、494. 目标和、474.一和零

59 阅读1分钟

1049. 最后一块石头的重量 II

1. first idea

half:=sum(stones) //2

To fill the bag whose capacity is half as much as possible.

If we can't fill the bag completely, it means that there is still one left stone.

class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        half = sum(stones) // 2

        dp = [[0] * (half + 1) for _ in range(len(stones))]

        for obj_idx in range(len(stones)):
            for tmp_cap in range(half + 1):
                if tmp_cap < stones[obj_idx]:
                    # 不够装
                    dp[obj_idx][tmp_cap] = dp[obj_idx - 1][tmp_cap]
                else:
                    # 够装
                    dp[obj_idx][tmp_cap] = max(dp[obj_idx - 1][tmp_cap], dp[obj_idx - 1][tmp_cap - stones[obj_idx]] + stones[obj_idx])
        
        return sum(stones) - (2 * dp[-1][-1])

494. 目标和

1. first idea

dp[i][tmp_target] denotes that given nums[:i+1],the number of the equations which can equals to tmp_target.

2. doc reading

代码随想录 (programmercarl.com)

{partApartB=targetpartA+partB=sum\begin{cases}partA-partB=target\\ partA+partB=sum\end{cases}

so partA=sum+target2partA=\frac{sum + target}{2} and partB=sumtarget2partB=\frac{sum-target}{2}.

Then, we can regard partApartA as the bag capacity.

The nums can be regard as the objects' prices.

However, the meaning of elements in the dp is different:

dp[i][j] denotes that the number of compositions that equal to temporary capacity j given nums[:i+1].

So the recursion is as follow:

dp[i][j]=dp[i1][jnums[i]]+dp[i1][j]dp\left[ i\right] \left[ j\right] =dp\left[ i-1\right] \left[ j-nums\left[ i\right] \right] +dp\left[ i-1\right] \left[ j\right]

There are only 2 choice, add nums[i] or skip nums[i].

But each choice need to be counted.

Additionally, there are still two return conditions:

  1. If sum+targetsum+target cannot be divided by 22. It means that the partApartA could never be filled by the sub-list of nums exactly.
  2. If target>sumtarget > sum, please don't waste time, return 0 at once.
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        if abs(target) > sum(nums):
            return 0
        if (sum(nums) + target) % 2 == 1:
            return 0
        partA = (sum(nums) + target) // 2
        dp = [[0] * (partA + 1) for _ in range(len(nums) + 1)]  # 因为递推式都需要上一层来确定,且第一层不能直接确定,我们就多加一行。
        # 初始化
        dp[0][0] = 1  # 如果没有数字,且partA为0,那就只有一种组合就是啥都没有。
        # print(dp)
        for obj_idx in range(1, len(nums) + 1):
            for tmp_cap in range(0, partA + 1):
                dp[obj_idx][tmp_cap] = dp[obj_idx - 1][tmp_cap]
                if tmp_cap >= nums[obj_idx - 1]:
                    dp[obj_idx][tmp_cap] += dp[obj_idx - 1][tmp_cap - nums[obj_idx - 1]]
        # print(dp)
        return dp[-1][-1]

474. 一和零

1. doc reading

代码随想录 (programmercarl.com)

Roll array is better in this question.

class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        # 滚动数组
        # 每个物品(字符串)的价值是1.
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        for tmp_str in strs:
            str_list = list(tmp_str)
            zero_count = 0
            one_count = 0
            for char in str_list:
                if char == '0':
                    zero_count += 1
                else:
                    one_count += 1
            for zero_cap in range(m, -1, -1):
                for one_cap in range(n, -1, -1):
                    if (zero_cap >= zero_count) and (one_cap >= one_count):
                        dp[zero_cap][one_cap] = max(dp[zero_cap][one_cap], dp[zero_cap - zero_count][one_cap - one_count] + 1)
        
        return dp[-1][-1]