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 <= numsi <= 1000
  • 0 <= sum(numsi) <= 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]
相关推荐
用户497863050739 分钟前
(一)小红的数组操作
算法·编程语言
怕浪猫3 小时前
Electron 系列文章封面图
算法·架构·前端框架
黄忠4 小时前
01-系统架构设计-LangGraph状态机与多源异构RAG
python
zzzzzz3104 小时前
假如我是掘金管理员,我先给评论区装个'代码审查'系统
python·程序员·机器人
砍材农夫5 小时前
python环境|conda安装和使用(2)
后端·python
徐小夕5 小时前
JitWord 3.0 正式发布,高精度Word异构解析+复杂组件兼容,打造web端协同Word编辑器
前端·vue.js·算法
程序员龙叔17 小时前
编写高质量 Skill 系列 -- 如何设计需求分析与用例生成的 SKILL
自动化测试·软件测试·python·软件测试工程师·接口测试·性能测试·skill·ai测试
用户83562907805120 小时前
使用 Python 操作 Word 内容控件
后端·python
通信小呆呆20 小时前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人