1.322. 零钱兑换
(1)确定数组和下标
dp[ j ]表示凑成总金额为 j 最少需要的硬币数
(2)递推关系式
dp[ j ] = min(dp[ j ], dp[ j - coin[ i ]] + 1)
(3)初始化
dp[0] = 0,其余位置因为会比较取最小值,初始化为’inf’
(4)遍历顺序
组合的完全背包(?),先物品后背包,都从前往后
(5)打印数组
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
coins.sort()
for i in range(len(coins)):
if coins[i] <= amount: #可以不用加这个判断条件
for j in range(coins[i], amount + 1):
dp[j] = min(dp[j], dp[j - coins[i]] + 1)
if dp[amount] == float('inf'):
return -1
else:
return dp[amount]
注意点:本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以!但我认为这道题是求最少硬币数量,无关顺序,所以还是觉得是组合问题。
2.279.完全平方数
(1)确定数组和下标
dp[ j ] 表示和为 j 的最少完全平方数
(2)递推关系式
dp[ j ] = min(dp[ j ], dp[ j - i ] + 1),i 是遍历的完全平方数
(3)初始化
dp[0] = 0,其他取’inf’
(4)遍历顺序
无关顺序,按照组合完全背包,先物品后背包
(5)打印数组
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]
3.139.单词拆分
(1)确定数组和下标
dp[ i ]表示字符串长度为 i,是否可以拆分为一个或者多个在字典中出现的单词
(2)递推关系式
如果区间[j,i]区间内的子串出现在字典里并且dp[j] = True,那么dp[i] = True
(3)初始化
dp[0] = True,因为是递推的根基,否则后面都为False
(4)遍历顺序
因为单词可以重复出现,所以是完全背包问题。这道题求的是排列数,因为单词需要按照顺序排列才能组成字符串 s
(5)打印数组
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
#查找效率更高,set时间复杂度为o(1),而list为o(n)
wordSet = set(wordDict)
n = len(s)
dp = [False] * (n + 1)
dp[0] = True
#排列,先背包后物品
for i in range(1, n + 1):
for j in range(i):
if dp[j] and s[j:i] in wordSet:
dp[i] = True
break
return dp[n]
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
dp = [False] * (len(s) + 1)
dp[0] = True
for j in range(1, len(s) + 1):
for word in wordDict:
if j >= len(word):
dp[j] = dp[j] or (dp[j - len(word)] and s[j - len(word): j] == word)
return dp[len(s)]
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
#按照单词长度排序
wordDict.sort(key = lambda x: len(x))
dp = [False] * (len(s) + 1)
dp[0] = True
for j in range(1, len(s) + 1):
for word in wordDict:
#剪枝
if len(word) > j:
break
dp[j] = dp[j] or (dp[j - len(word)] and s[j - len(word):j] == word)
return dp[-1]
4.多重背包
C, M = [int(x) for x in input().split()]
weight = [int(x) for x in input().split()]
value = [int(x) for x in input().split()]
nums = [int(x) for x in input().split()]
dp = [0] * (C + 1)
for i in range(M):
#背包倒序
for j in range(C, weight[i] - 1, -1):
for k in range(1, nums[i] + 1):
if k * weight[i] > j:
break
dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i])
print(dp[C])
卡码网一直显示超时。