参考解答:动态规划套路详解
思路1:递归。会超时。
时间复杂度为 O(kn)
空间复杂度O(n)
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
def helper(coins, amount): # 可以合并内部函数和本身
if amount == 0: return 0
ans = 2 ** 31
for c in coins:
newAmount = amount - c
if newAmount < 0: continue
subPro = helper(coins, newAmount) # 获得newAmount的最小硬币数
if subPro == -1: continue
ans = min(ans, subPro + 1) # 获得amount(=newAmount+c)的最小硬币数
return ans if ans != 2 ** 31 else -1
return helper(coins, amount)
思路2:带记忆的递归。有时会超时。
时间复杂度为 O(k*n)
空间复杂度O(n)
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
memo = {} # 记录不同目标值对应的最小硬币数
def helper(coins, amount):
if amount == 0: return 0
if amount in memo.keys(): return memo[amount]
ans = 2 ** 31
for c in coins:
newAmount = amount - c
if newAmount < 0: continue
subPro = helper(coins, newAmount)
if subPro == -1: continue
ans = min(ans, subPro + 1)
memo[amount] = ans if ans != 2 ** 31 else -1
return memo[amount]
return helper(coins, amount)
思路3:动态规划。
时间复杂度为 O(k*n)
空间复杂度O(n)
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [2**31 for _ in range(amount+1)] # 记录每个目标值的最小硬币数,初始化为最大
dp[0] = 0
for i in range(1,amount+1):
for c in coins:
newAmount = i-c
if newAmount>=0:
dp[i] = min(dp[i],dp[newAmount]+1) # dp[i]有很多,只保留最小的
return dp[-1] if dp[-1]!=2**31 else -1 # 若未修改则输出-1