给定数组 arr,arr 中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数 aim 代表要找的钱数,求换钱有多少种方法。
【例如】arr = [ 5, 10, 25, 1 ] , aim = 0 ;返回 1
组成 0 元的方法有 1 种,就是所有面值的货币都不用
arr = [ 5, 10, 25, 1 ] , aim = 15 ;返回 6
- [ 5, 5, 5 ]
- [ 5, 10 ]
- [10, 1, 1, 1, 1, 1 ]
- [ 5, 5, 1, 1, 1, 1, 1 ]
- [ 5, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1 ]
- [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
arr = [ 3, 5 ] , aim = 2 ;返回 0
任何方法都无法组成 2 元。
动态规划模型:L --> R
每种银币都可以使用 0 ~ n,但是保证 coins[i] * count <= aim
arr = [ 5, 10, 25, 1 ] , aim = 15 ;返回 6
- 使用 0 张 5元的硬币,让 arr = [ 10, 25, 1 ] 组成 aim = 15 ;结果为 res1
- 使用 1 张 5元的硬币,让 arr = [ 10, 25, 1 ] 组成 aim = 10 ;结果为 res2
- 使用 2 张 5元的硬币,让 arr = [ 10, 25, 1 ] 组成 aim = 5 ;结果为 res3
- 使用 3 张 5元的硬币,让 arr = [ 10, 25, 1 ] 组成 aim = 0 ;结果为 res4
- res = res1 + res2 + res3 + res4
# index 每次处理使用货币下边【变量】;process1 每次调用处理一个货币
# aim 剩余目标值【变量】
def process1(arr, index, aim):
if index == len(arr):
return 1 if aim == 0 else 0
res = 0
count = 0
while arr[index] * count <= aim:
res += process1(arr, index + 1, aim - arr[index] * count)
count += 1
return res
def coins1(arr, aim):
if not arr or aim < 0:
return 0
return process1(arr, 0, aim)
print(coins1[5, 10, 25, 1],15)
index, aim 是变量,所以 dp 是个二维表
def coins2(arr, aim):
if not arr or aim < 0:
return 0
dp = [[0] * (aim + 1) for _ in range(len(arr) + 1)]
for i in range(len(arr) + 1):
dp[i][0] = 1
for i in range(len(arr) - 2, -1, -1):
for j in range(aim + 1):
count = 0
while arr[i] * count <= j and (j - arr[i] * count) >= 0:
dp[i][j] += dp[i + 1][j - arr[i] * count]
count += 1
return dp[0][aim]
def coins2(arr, aim):
if not arr or aim < 0:
return 0
dp = [[0] * (aim + 1) for _ in range(len(arr))]
# base case aim = 0 是结果就是 1
for i in range(len(arr)):
dp[i][0] = 1
# base case 只使用 arr[0] 时,只有 aim = arr[0] * i 时 等于 1
for i in range(1, aim + 1):
if arr[0] * i < aim + 1:
dp[0][arr[0] * i] = 1
#
for i in range(1, len(arr)):
for j in range(1, aim + 1):
count = 0
while arr[i] * count <= j:
dp[i][j] += dp[i - 1][j - arr[i] * count]
count += 1
return dp[len(arr) - 1][aim]
斜率优化
def coins3(arr, aim):
if not arr or aim < 0:
return 0
dp = [[0] * (aim + 1) for _ in range(len(arr))]
for i in range(len(arr)):
dp[i][0] = 1
for i in range(1, aim + 1):
if arr[0] * i < aim + 1:
dp[0][arr[0] * i] = 1
for i in range(1, len(arr)):
for j in range(1, aim + 1):
dp[i][j] = dp[i - 1][j]
dp[i][j] += dp[i][j - arr[i]] if (j - arr[i]) >= 0 else 0
return dp[len(arr)-1][aim]