什么是背包问题
背包问题是一类经典的动态规划问题,它非常灵活。
背包问题的特征: 一般有个target,求组成target的组合方式等等
分类: 0-1背包问题、完全背包问题
0-1背包问题:数组中的元素不能重用,外层遍历数组,内层逆序遍历
target。
完全背包问题:数组中的元素可以重复使用
- 不考虑数组的顺序,外层遍历数组,内层顺序遍历target
- 考虑数组的顺序,外层遍历target,内层遍历数组
leetcode494:目标和
0-1背包问题
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
sum_n = sum(nums)
neg = (sum_n - target) % 2
if neg or sum_n < target:
return 0
target = (sum_n - target) // 2
dp = [0] * (target+1)
dp[0] = 1
for num in nums:
for i in range(target, num-1, -1):
dp[i] = dp[i-num] + dp[i]
return dp[-1]
leetcode518
完全背包问题
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
#完全背包问题
class Solution(object):
def change(self, amount, coins):
"""
:type amount: int
:type coins: List[int]
:rtype: int
"""
dp = [0] * (amount+1)
dp[0] = 1
for coin in coins:
for j in range(coin, amount+1):
dp[j] = dp[j] + dp[j-coin]
return dp[-1]
leetcode322. 零钱兑换
完全背包问题:
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的
#完全背包问题
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
n = len(coins)
dp = [float("inf")] * (amount+1)
dp[0] = 0 #dp表示填满i的背包最少需要多少coin
for coin in coins:
for i in range(coin, amount+1):
dp[i] = min(dp[i], dp[i-coin]+1)
return dp[-1] if dp[-1] != float("inf") else -1
416. 分割等和子集
0-1背包问题:
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
#0-1背包问题
class Solution:
def canPartition(self, nums: List[int]) -> bool:
sum_n = sum(nums)
if sum_n % 2:
return False
target = sum_n // 2
dp = [False] * (target+1)
dp[0] = True
for num in nums:
for i in range(target, num-1, -1):
dp[i] = dp[i] or dp[i-num]
return dp[-1]
377. 组合总和 Ⅳ
这道题考虑顺序:
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
#这道题考虑顺序
class Solution(object):
def combinationSum4(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
n = len(nums)
dp = [0] * (target+1)
dp[0] = 1
for i in range(target+1):
for num in nums:
if num <= i:
dp[i] = dp[i] + dp[i-num]
return dp[-1]