322. 零钱兑换
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
这句话结合本题 大家要好好理解。
视频讲解:https://www.bilibili.com/video/BV14K411R7yv
https://programmercarl.com/0322.零钱兑换.html
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
思考
本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。
所以本题并不强调集合是组合还是排列。背包和物品的遍历先后不重要。
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
# dp[i] 组成总数为i的的硬币最小组合长度
dp = [float('inf')] * (amount+1)
dp[0] = 0
# 先物品再背包
for coin in coins:
for i in range(1,amount+1):
if i-coin >=0:
dp[i] = min(dp[i-coin]+1,dp[i])
if dp[-1] == float('inf'):
return -1
else:
return dp[-1]
279.完全平方数
本题 和 322. 零钱兑换 基本是一样的,大家先自己尝试做一做
视频讲解:https://www.bilibili.com/video/BV12P411T7Br
https://programmercarl.com/0279.完全平方数.html
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9
思考
跟零钱兑换一样,完全背包问题。
本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。
所以本题并不强调集合是组合还是排列。背包和物品的遍历先后不重要。
class Solution:
def numSquares(self, n: int) -> int:
# dp[i] 容量i的背包,装满的最少组合数
dp = [float('inf')] * (n+1)
dp[0] = 0
#先物品再背包 求组合数
for j in range(1,n+1):
if j**2 > n:
break
for i in range(1,n+1):
if i>=j**2:
dp[i] = min(dp[i],dp[i-j**2]+1)
return dp[-1]
139.单词拆分
视频讲解:https://www.bilibili.com/video/BV1pd4y147Rh
https://programmercarl.com/0139.单词拆分.html
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。
注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
思考
物品可以重复选取,完全背包问题。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
而本题其实我们求的是排列数,为什么呢。 拿 s = "applepenapple", wordDict = ["apple", "pen"] 举例。
"apple", "pen" 是物品,那么我们要求 物品的组合一定是 "apple" + "pen" + "apple" 才能组成 "applepenapple"。
"apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。
所以说,本题一定是 先遍历 背包,再遍历物品。
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
#dp[i] 表示 s[0:i]是否可以拆分 左闭右开
dp = [False]* (len(s)+1)
dp[0] = True
for i in range(1,len(s)+1):
for word in wordDict:
if i >=len(word):
#print(word,len(word),i)
dp[i] = dp[i-len(word)] and s[i-len(word):i] == word
if dp[i]:
break
return dp[len(s)]
关于多重背包,你该了解这些!
https://programmercarl.com/背包问题理论基础多重背包.html
背包问题总结篇!
https://programmercarl.com/背包总结篇.html
标签:背包,apple,41,322,遍历,物品,279,com,dp From: https://www.cnblogs.com/forrestr/p/18289116