换零钱是一个典型的动态规划场景。
322. Coin Change
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1
题目解析:
在现实场景中,换零钱用贪心算法就行~但是在题目中不可以。
动态规划的思路就是想换amount的零钱,我们需要从1开始步步为营,先解决每一个子问题。由于货币的单位未知,有可能许多面值无法兑换出来,需要做一些结果为-1的处理。
动态规划的思路大概是这样,代码有些啰嗦,可以精简一些。
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
if not coins:
return -1
n = len(coins)
coins.sort()
dp = [-1] * (amount+1)
dp[0] = 0
# 此题需要解决 无法组成的情况
for i in range(1, amount+1):
min_ = i
for coin in coins:
if coin > i:
break
if dp[i - coin] != -1:
min_ = min(min_, dp[i - coin])
if min_ == i:
dp[i] = -1
else:
dp[i] = min_ + 1
return dp[-1]
279. Perfect Squares
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...
) which sum to n.
题目解析:
腚眼一看,这不也是在给n这个数值换零钱为 coins相当于一个个平方数。
当然由于平方等数学因素,我们可知道所有候选平方数,这道题也有非DP的解法,性能也不错,用一个队列直接去拼凑n。
这里我们只讨论DP算法,还是从1开始步步为营,对于每一个i来说,仍然是去 i - coin (这道题中coin相当于一个个平方数)的dp数组中查最小值。直接看代码吧,这个专题其实还比较简单的。
class Solution:
def numSquares(self, n: int) -> int:
dp = [0] * (n+1)
sq = 0
for i in range(1, n+1):
if i == (sq+1) ** 2:
sq += 1
dp[i] = 1
continue
# 否则的话 还是小于(sq+1)^2
min_ = i
stop = i // 2
for j in range(sq, 0, -1):
min_ = min(min_, dp[i-j*j])
if min_ == 1:
break
dp[i] = min_ + 1
return dp[n]