class Solution:
def change(self, amount: int, coins: List[int]) -> 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[-1]
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp=[0]*(target+1)
dp[0]=1
for j in range(target+1):
for i in range(len(nums)):
if j>=nums[i]:
dp[j]+=dp[j-nums[i]]
return dp[-1]
'''按照518题的注释,我们可以得出,这是一个可以重复使用元素,并且求排列数的问题。
那么就可以按照我们的模板,先正序遍历背包(为了重复),再遍历物品(为了排列)。'''
注意第二个for循环里的if判断。本质上和组合数的第二个for是一样的。
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp=[2**32]*(amount+1)
dp[0]=0
for i in range(len(coins)):
for j in range(coins[i],amount+1):
dp[j]=min(dp[j],dp[j-coins[i]]+1)
if dp[-1]==2**32:#这里要加一个判断,如果最后结果为初始化的值,就说明没法兑换。
return -1
return dp[-1]
'''这题完全可以参考343题的思考方式。只不过注意,求的是最小。所以dp的初始化应该初始为一个非常大的值。如果求最大的话,全为正数时,初始化为0,如果有负数存在,初始化为最小数
同时递推公式变成了min。这题也是一个重复的,但是这个题不需要强调是排列还是组合,我们只要找到最小长度就ok。'''
class Solution:
def numSquares(self, n: int) -> int:
dp=[2**32]*(n+1)
dp[0]=0
for i in range(int(n**(1/2))+1):
for j in range(i**2-1,n+1):
dp[j]=min(dp[j],dp[j-i*i]+1)
return dp[-1]
'''和322题一样类型,只不过变更了一下。没有coin的list了,需要我们自己选一下。'''
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
dp=[False]*(len(s)+1)
dp[0]=True
for j in range(1,len(s)+1):
for i in range(j):
if dp[i] and s[i:j] in wordDict:#注意这里不是j+1,因为我们统计的就是从i到j-1这个长度的字符串。把结果赋给dp[j]
dp[j]=True
return dp[-1]
'''题目意思大概可以理解为,从wordDict中选择合适的str,能不能把s这个背包塞满。wordDict里面可以重复使用。
那么接下来就是看是排列还是组合了。个人感觉排列好一点,其实都可以。
接下来是初始化,dp[0]要是T,否则剩下的永远是F。其他的都为F。那么递推公式怎么得到的呢?
当i<j,如果dp[i]是T,并且s的下标从i到j的时候,如果这段字符串恰巧也在wordDict中,那么就说明dp[j]也是T。'''