leetcode-零钱问题

最朴素的版本

class Solution(object):

    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        n = len(coins)
        if n <= 0 or amount < 0: return -1
        d = [[float('inf')] * (amount + 1) for _ in range(n)]
        d[0][0] = 0
        ## 如果需要兑换的钱为0,则不需要硬币
        for i in range(n): d[i][0] = 0

        ## 第一行初始化 反复取第一枚硬币所能满足的amount
        for j in range(1, amount + 1):
            d[0][j] = float('inf')
            if j - coins[0] >= 0 and d[0][j - coins[0]] != float('inf'):
                d[0][j] = d[0][j - coins[0]] + 1
        # print('debug-1', d)

        for i in range(1, n):
            # for j in range(1, amount + 1): ## 步涌每个都遍历 这个也是进阶版不是原始
            for j in range(1, amount+1):
                k = 0
                while k*coins[i] <= j :
                    d[i][j] = min(d[i][j], d[i-1][j-k*coins[i]]+k)
                    k += 1
        # print('debug-2',d)
        return d[-1][-1] if d[-1][-1] != float('inf') else -1

优化后版本1

class Solution:
    def minMoney(self , arr , aim ):
        # write code here
        n = len(arr)
        if n<=0 or aim <0: return -1
        d = [[float('inf')] * (aim + 1) for _ in range(n)]
        d[0][0] = 0
        ## 如果需要兑换的钱为0,则不需要硬币
        for i in range(n):
            d[i][0] = 0
        
        ## 第一行初始化 反复取第一枚硬币所能满足的aim
        for j in range(1, aim+1):
            d[0][j] = float('inf')
            if j - arr[0] >=0 and d[0][j-arr[0]] !=float('inf'):
                d[0][j] = d[0][j-arr[0]] + 1
            

        for i in range(1, n):
            for j in range(1, aim + 1):
                left = float('inf')
                if j- arr[i] >=0 and d[i][j-arr[i]] != float('inf'):
                    left = d[i][j - arr[i]] + 1
                d[i][j] = min(d[i-1][j], left)
                
        return d[-1][-1] if d[-1][-1] != float('inf') else -1

二维转一维优化

class Solution(object):
    def coinChange(self, coins, amount):
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        
        for coin in coins:
            for x in range(coin, amount + 1):
                dp[x] = min(dp[x], dp[x - coin] + 1)
        return dp[amount] if dp[amount] != float('inf') else -1 

回溯版本 => 记忆化搜索 => 二维表 =>滚动数组
无限放取+方法数
arr里都是正数,没有重复,每一个值代表一种货币,每一种都可以用无限张,最终要找零钱是aim,
找零方法数放回

递归 入参 process(arr, index, rest)
自由使用arr[index…] 所有的面值
需要搞定的钱数rest
返回找零的方法数

终止条件,决定dp表的一些初始位置,非常重要

if index == arr.length:
    resturn rest == 1 if rest==0 else 0

递归方程

way = 0
zhang = 0
while arr[index] * zhang <= rest:
    ways += process(arr, index+1, rest-arr[indext]*zhang)
    zhang += 1
    return way

只能取一次,最少的零钱数量返回
终止条件:

if rest <0: return -1
if rest=0: return 0
if index == length: return -1

一般情况:

p1= process( arr, index+1, rest)
p2 = process(arr, index+1, rest - arr[index])
if (p1== -1 and p2==-1):
    return -1
else:
    if p1==-1:
        return p2+1
    if p2==-1:
        return p1
    return min(p1, p2+1)
    
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值