学习资料:https://programmercarl.com/背包问题理论基础完全背包.html#算法公开课
相比于01背包,完全背包中每个物品都可以无限次的放入
组合:先遍历物品,再逆序遍历背包
排列:先逆序遍历背包,再遍历物品
学习记录
卡码网52.携带研究资料(dp[i]代表当重量为i时的最大价值)
点击查看代码
n, v = map(int,input().split())
weight=[]
value = []
for i in range(n):
wi, vi = map(int, input().split())
weight.append(wi)
value.append(vi)
# 构建dp数组
dp = [0]*(v+1)
for i in range(n):
for j in range(weight[i], v+1):
dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
print(dp[v])
518.零钱兑换2(dp[i]代表总金额为i时的组合数;我感觉当问方法数或者路线时,递归方程一般是自加)
点击查看代码
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 i in range(len(coins)):
for j in range(coins[i], amount+1):
dp[j] += dp[j-coins[i]]
return dp[amount]
377.组合总和4(dp[i]代表总和为i时的组合个数,完全背包+排列)
点击查看代码
class Solution(object):
def combinationSum4(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
# 相当于动态规划的完全背包的排列问题,因为要考虑顺序,则先遍历背包再遍历物品
dp = [0]*(target+1)
dp[0]=1
for j in range(1, target+1):
for i in range(len(nums)):
if j >= nums[i]:
dp[j] += dp[j-nums[i]]
return dp[target]
70.卡码网爬楼梯(dp[i]代表爬了i阶有多少方法,完全背包+排列)
点击查看代码
def climbStairs(n,m):
"""
还是完全背包的排列问题,先遍历背包再遍历物品,dp[j]是背包容量为j的时候的走法;
递推公式里自加的原因是,比如一次能爬一阶或者爬两阶,
那么到达当前位置的方法数等于到达前一阶的方法数加上到达前两阶的方法数,因为从前一阶到当前位置就一种走法
"""
dp = [0]*(n+1)
dp[0]=1
for j in range(1, n+1):
for i in range(1, m+1):
if j>=i:
dp[j] += dp[j-i]
return dp[n]
if __name__ == "__main__":
n, m = map(int, input().split())
print(climbStairs(n, m))
322.零钱兑换(dp[i]代表当总金额为i时的最小硬币数,完全背包+组合;求最小数量,就设置dp每个值为无穷大,而dp[0]=0)
点击查看代码
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
dp = [float('inf')]*(amount+1) # 设置初始值均为无穷大
dp[0] = 0
for i in range(len(coins)):
for j in range(coins[i], amount+1):
if dp[j-coins[i]] != float('inf'): # 如果前一项不是无穷大,则进行状态转移
dp[j] = min(dp[j], dp[j-coins[i]]+1)
if dp[amount] == float('inf'):
return -1
else:
return dp[amount]
279.完全平方数(dp[j]代表和为j时,最少是由多少个完全平方数组成的,这个个数)
点击查看代码
class Solution(object):
def numSquares(self, n):
"""
:type n: int
:rtype: int
"""
dp = [float('inf')]*(n+1)
dp[0]=0
for i in range(1, int(n**0.5)+1):
for j in range(i*i, n+1):
dp[j] = min(dp[j], dp[j-i*i]+1)
return dp[n]
139.单词拆分(dp[j]代表字符串长度为j时,是否可以拆分为字典中出现的单词,这个是布尔变量true/false)
点击查看代码
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
# 这可以用完全背包的排列问题思考
wordSet = set(wordDict)
n = len(s)
dp = [False]*(n+1)
dp[0] = True
for j in range(1, n+1): # 遍历背包
for i in range(j): # 遍历单词
if dp[i] and s[i:j] in wordSet:
dp[j] = True
break
return dp[n]
PS:难爆了,根本听不懂,我要多刷呀
颓废了三天,因为昨天面试最简单的二叉树的最大深度都忘了,没有复习二叉树没想到24天就忘光了,惭愧
今天赶紧回顾了一下,后序遍历(左右根)先求左右节点的高度,他们中的最大值加1就是该节点的高度,其中是用递归的方法来计算左右子树的高度滴
加油!多回顾,我可以的!
今天天气不好胃口不好心情不好,所以要早点下班恢复元气,今天的内容明天来补