2025-2-27-4.10 动态规划(0-1 背包问题)

文章目录

4.10 动态规划(0-1 背包问题)

0-1 背包问题,现在有点明了了,以前只觉得高大上,现在看来就是一个固定的模型思路,体积有限,物品有限,获取在固定体积下能得到的最大的物品价值。

原视频讲解链接

494. 目标和

题目链接

给你一个非负整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3

输出:5

解释:一共有 5 种方法让最终目标和为 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

示例 2:

输入:nums = [1], target = 1

输出:1

提示:

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

题目解析:有一定的数学推导,具体看灵神的题解,不难理解。

方法一:递归

python 复制代码
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:

        """
        方法一:递归
        时间复杂度:O(nm),其中 n 为 nums 的长度,m 为 nums 的元素和减去 target 的绝对值。
            由于每个状态只会计算一次,动态规划的时间复杂度 = 状态个数 × 单个状态的计算时间。
            本题状态个数等于 O(nm),单个状态的计算时间为 O(1),所以动态规划的时间复杂度为 O(nm)。
        空间复杂度:O(nm)。保存多少状态,就需要多少空间。
        """

        s = sum(nums) - abs(target)
        if s < 0 or s % 2:
            return 0
        m = s // 2

        @cache #缓存装饰器,避免重复计算 dfs 的结果
        def dfs(i: int, c: int) -> int:
            if i < 0:
                return 1 if c == 0 else 0
            if c < nums[i]:
                return dfs(i - 1, c)
            return dfs(i - 1, c) + dfs(i - 1, c - nums[i]) # 不选 + 选
        
        return dfs(len(nums) - 1, m)
        

方法二:递推

python 复制代码
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:

        """
        方法二:递推
        时间复杂度:O(nm),
            其中 n 为 nums 的长度,
            m 为 nums 的元素和减去 target 的绝对值。
        空间复杂度:O(nm)。保存多少状态,就需要多少空间。
        """

        s = sum(nums) - abs(target)
        if s < 0 or s % 2:
            return 0
        m = s // 2
        n = len(nums)

        f = [[0] * (m + 1) for _ in range(n+1)]
        f[0][0] = 1

        for i, x in enumerate(nums):
            for c in range(m+1):
                if c < x:
                    f[i + 1][c] = f[i][c]
                else:
                    f[i + 1][c] = f[i][c] + f[i][c - x]
        return f[n][m]
        

方法三:递推+滚动数组

python 复制代码
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:


       
        """
        方法三:递推+滚动数组
        时间复杂度:O(nm),
            其中 n 为 nums 的长度,
            m 为 nums 的元素和减去 target 的绝对值。
        空间复杂度:O(m)。保存多少状态,就需要多少空间。
        """

        s = sum(nums) - abs(target)
        if s < 0 or s % 2:
            return 0
        m = s // 2
        n = len(nums)

        f = [[0] * (m + 1) for _ in range(2)]
        f[0][0] = 1

        for i, x in enumerate(nums):
            for c in range(m+1):
                if c < x:
                    f[(i + 1)%2][c] = f[i%2][c]
                else:
                    f[(i + 1)%2][c] = f[i%2][c] + f[i%2][c - x]
        return f[n%2][m]
 

方法四:递推+单个数组

python 复制代码
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:

        """
        方法四:递推+简化数组
        时间复杂度:O(nm),
            其中 n 为 nums 的长度,
            m 为 nums 的元素和减去 target 的绝对值。
        空间复杂度:O(m)。保存多少状态,就需要多少空间。
        """

        s = sum(nums) - abs(target)
        if s < 0 or s % 2:
            return 0
        m = s // 2
        n = len(nums)

        f = [1] + [0] * m

        for x in nums:
            for c in range(m,x-1,-1):
                    f[c] += f[c - x]
        return f[m]
相关推荐
火兮明兮9 分钟前
Python训练第四十三天
开发语言·python
闪电麦坤951 小时前
数据结构:递归的种类(Types of Recursion)
数据结构·算法
互联网杂货铺1 小时前
完美搭建appium自动化环境
自动化测试·软件测试·python·测试工具·职场和发展·appium·测试用例
Gyoku Mint2 小时前
机器学习×第二卷:概念下篇——她不再只是模仿,而是开始决定怎么靠近你
人工智能·python·算法·机器学习·pandas·ai编程·matplotlib
纪元A梦2 小时前
分布式拜占庭容错算法——PBFT算法深度解析
java·分布式·算法
莱茵菜苗2 小时前
Python打卡训练营day46——2025.06.06
开发语言·python
爱学习的小道长2 小时前
Python 构建法律DeepSeek RAG
开发语言·python
px不是xp2 小时前
山东大学算法设计与分析复习笔记
笔记·算法·贪心算法·动态规划·图搜索算法
luojiaao2 小时前
【Python工具开发】k3q_arxml 简单但是非常好用的arxml编辑器,可以称为arxml杀手包
开发语言·python·编辑器