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

LeetCode 1049. 最后一块石头的重量II
题目链接:1049. 最后一块石头的重量 II - 力扣(LeetCode)代码随想录算法训练营第四十二天|1049. 最后一块石头的重量II、494. 目标和、474. 一和零_第1张图片

我们两部分考虑,一部分是正的,一部分是负的,这道题是想求最平衡的时候

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:其实就是求离target最近的一个和

2)确定递推公式:一维数组,所以从后向前,这样对于每个物品只会放一次。

3)确定初始值:dp[0][0]肯定是0,一点空间也没,一件物品也没,当然价值为0

4)确定遍历的数:

5)带入验证一下

代码:

#python   一维数组
class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        total_sum = sum(stones)
        target = total_sum // 2
        dp = [0 for _ in range(target + 1)]   //一维数组
        dp[0] = 0
        for stone in stones:  //先遍历重量
            for j in range(target, stone - 1, - 1):
                dp[j] = max(dp[j], dp[j - stone] + stone)  //比一比当前最大能装多少
        return total_sum - 2 * dp[-1] //最后一个是最接近与中和的数

LeetCode 494. 目标和
题目链接:494. 目标和 - 力扣(LeetCode)代码随想录算法训练营第四十二天|1049. 最后一块石头的重量II、494. 目标和、474. 一和零_第2张图片

第一反应是一个DFS,回溯法,但是就别回了,直接DP,我们可以不断赋值,得到一个最大的表达式数组。

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:同样的就是求离target最近的一个和

2)确定递推公式:一维数组,所以从后向前,这样对于每个物品只会放一次。

3)确定初始值:dp[0]应该为1,此时只有一种选择

4)确定遍历的数:内循环从大到小

5)带入验证一下

代码:

#python
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        total_sum = sum(nums)  # 计算nums的总和
        if abs(target) > total_sum:
            return 0  # 此时没有方案
        if (target + total_sum) % 2 == 1:
            return 0  # 此时没有方案
        target_sum = (target + total_sum) // 2  # 目标和
        dp = [0] * (target_sum + 1)  # 创建动态规划数组,初始化为0
        dp[0] = 1  # 当目标和为0时,只有一种方案,即什么都不选
        for num in nums:
            for j in range(target_sum, num - 1, -1):
                dp[j] += dp[j - num]  # 状态转移方程,累加不同选择方式的数量
        return dp[target_sum]  # 返回达到目标和的方案数  

LeetCode 474. 一和零
题目链接:474. 一和零 - 力扣(LeetCode)代码随想录算法训练营第四十二天|1049. 最后一块石头的重量II、494. 目标和、474. 一和零_第3张图片

这道题感觉也是DFS,我们用DP来做,思路就是遍历所有的str,使用collections里的counter来计算一下1与0的个数,随后我们用一个二维数组dp[i][j]来得到一个子集元素最多的满足条件的子集,(i表示1的个数,j表示0的个数)。

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:

2)确定递推公式:二维数组,赋值的时候都是0,后面要求最大的,因此要么是当前的个数,要么是从前来的(dp[i - one_num][j - zero_num]从这里推过来,当然个数就要+1)

3)确定初始值:dp[0]应该为0

4)确定遍历的数:都是逆向的,其实这和前面的题目有点像,像两个内循环

d5)带入验证一下

代码:

#python
class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
        for st in strs:
            one_num = st.count('1')  //1的个数
            zero_num = len(st) - one_num  //0的个数
            for i in range(m, zero_num - 1, -1):   //逆向
                for j in range(n, one_num - 1, - 1):   //逆向
                    dp[i][j] = max(dp[i][j], dp[i - zero_num][j - one_num] + 1)
        return dp[m][n]

你可能感兴趣的:(算法)