Leetcode刷题——动态规划练习(0-1背包系列)

张开发
2026/4/8 9:36:11 15 分钟阅读

分享文章

Leetcode刷题——动态规划练习(0-1背包系列)
动态规划0-1背包系列102目标和题目描述给定一个正整数数组 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 31 - 1 1 1 1 31 1 - 1 1 1 31 1 1 - 1 1 31 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题目求解classSolution:deffindTargetSumWays(self,nums:List[int],target:int)-int:# 使用动态规划# 0-1背包 刚好装满 背包的方案数量# 前面 的数字之和A# 前面- 的数字之和B# 满足 A - B target# 并且 A B sum(nums)# 则A targetsum / 2# 背包容量为A找 能恰好装满A容量的方案数itemtargetsum(nums)ifitem%2!0:return0# 找不到方案Aitem//2dp[0]*(A1)dp[0]1fornuminnums:foriinrange(A,num-1,-1):dp[i]dp[i-num]returndp[A]最后一块石头的重量题目描述有一堆石头每块石头的重量都是正整数。每一回合从中选出两块 最重的 石头然后将它们一起粉碎。假设石头的重量分别为 x 和 y且 x y。那么粉碎的可能结果如下如果 x y那么两块石头都会被完全粉碎如果 x ! y那么重量为 x 的石头将会完全粉碎而重量为 y 的石头新重量为 y-x。最后最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下就返回 0。示例输入[2,7,4,1,8,1]输出1解释先选出 7 和 8得到 1所以数组转换为 [2,4,1,1,1]再选出 2 和 4得到 2所以数组转换为 [2,1,1,1]接着是 2 和 1得到 1所以数组转换为 [1,1,1]最后选出 1 和 1得到 0最终数组转换为 [1]这就是最后剩下那块石头的重量。提示1 stones.length 301 stones[i] 1000题目求解大顶堆求解使用heapq默认是小顶堆全变为负数就是大顶堆了取值得时候取反。importheapqclassSolution:deflastStoneWeight(self,stones:List[int])-int:heap[-sforsinstones]heapq.heapify(heap)whilelen(heap)1:y-heapq.heappop(heap)x-heapq.heappop(heap)ifyx:heapq.heappush(heap,-(y-x))return-heap[0]ifheapelse0最后一块石头的重量 Ⅱ题目描述有一堆石头用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。每一回合从中选出任意两块石头然后将它们一起粉碎。假设石头的重量分别为 x 和 y且 x y。那么粉碎的可能结果如下如果 x y那么两块石头都会被完全粉碎如果 x ! y那么重量为 x 的石头将会完全粉碎而重量为 y 的石头新重量为 y-x。最后最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下就返回 0。示例 1输入stones [2,7,4,1,8,1]输出1解释组合 2 和 4得到 2所以数组转化为 [2,7,1,8,1]组合 7 和 8得到 1所以数组转化为 [2,1,1,1]组合 2 和 1得到 1所以数组转化为 [1,1,1]组合 1 和 1得到 0所以数组转化为 [1]这就是最优值。示例 2输入stones [31,26,33,21,40]输出5提示1 stones.length 301 stones[i] 100题目求解首先类似于上一题使用贪心模拟也可以做到但不是最优解使用DP0-1背包题目本质把石头分成两堆让两堆的总和尽可能的接近设总和 sum第一堆和 S第二堆和 sum - S最后剩余的重量就是sum - 2 * S 让S尽可能接近sum / 2但不超过sum / 2套进背包模型背包容量 sum / 2每个 石头重量 价值 stores[i]求不超过容量的最大价值最后答案 sum - 2 * dp[sum / 2]代码classSolution:deflastStoneWeightII(self,stones:List[int])-int:stones_sumsum(stones)targetstones_sum//2dp[0]*(target1)forstoneinstones:foriinrange(target,stone-1,-1):dp[i]max(dp[i],dp[i-stone]stone)returnstones_sum-2*dp[target]474. 一和零题目描述给你一个二进制字符串数组 strs 和两个整数 m 和 n 。请你找出并返回 strs 的最大子集的长度该子集中 最多 有 m 个 0 和 n 个 1 。如果 x 的所有元素也是 y 的元素集合 x 是集合 y 的 子集 。示例 1输入strs [“10”, “0001”, “111001”, “1”, “0”], m 5, n 3输出4解释最多有 5 个 0 和 3 个 1 的最大子集是 {“10”,“0001”,“1”,“0”} 因此答案是 4 。其他满足题意但较小的子集包括 {“0001”,“1”} 和 {“10”,“1”,“0”} 。{“111001”} 不满足题意因为它含 4 个 1 大于 n 的值 3 。示例 2输入strs [“10”, “0”, “1”], m 1, n 1输出2解释最大的子集是 {“0”, “1”} 所以答案是 2 。提示1 strs.length 6001 strs[i].length 100strs[i] 仅由 ‘0’ 和 ‘1’ 组成1 m, n 100题目求解classSolution:deffindMaxForm(self,strs:List[str],m:int,n:int)-int:dp[[0]*(n1)for_inrange(m1)]forsinstrs:sum_0s.count(0)sum_1s.count(1)forjinrange(m,sum_0-1,-1):forkinrange(n,sum_1-1,-1):dp[j][k]max(dp[j][k],dp[j-sum_0][k-sum_1]1)returndp[m][n]

更多文章