【每日一题】换钱方法数

给定数组 arr,arr 中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数 aim 代表要找的钱数,求换钱有多少种方法。

【例如】arr = [ 5, 10, 25, 1 ] , aim = 0 ;返回 1
组成 0 元的方法有 1 种,就是所有面值的货币都不用
arr = [ 5, 10, 25, 1 ] , aim = 15 ;返回 6

  1. [ 5, 5, 5 ]
  2. [ 5, 10 ]
  3. [10, 1, 1, 1, 1, 1 ]
  4. [ 5, 5, 1, 1, 1, 1, 1 ]
  5. [ 5, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1 ]
  6. [ 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]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值