2025-2-27-4.10动态规划(0-1背包问题)
- 开源代码
- 2025-09-20 10:30:01

文章目录 4.10 动态规划(0-1 背包问题)494. 目标和方法一:递归方法二:递推方法三:递推+滚动数组方法四:递推+单个数组 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 <= 200 <= nums[i] <= 10000 <= sum(nums[i]) <= 1000-1000 <= target <= 1000题目解析:有一定的数学推导,具体看灵神的题解,不难理解。
方法一:递归 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) 方法二:递推 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] 方法三:递推+滚动数组 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] 方法四:递推+单个数组 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]2025-2-27-4.10动态规划(0-1背包问题)由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“2025-2-27-4.10动态规划(0-1背包问题)”