Coin Change(硬币最少组合) python的动态规划实现记录

题目为给定不同面值的n种硬币,面值加起来等于一个特定的数m,求最少需要多少枚硬币实现。

这个问题如果使用暴力求解,需要穷举所有可以加起来等m的组合,时间复杂度为O(m^n)。

def coin_27_plus_1(x):
    coins = [2,5,7]
    len_s = [x//coin for coin in coins]

    sum = 0
    times = 0
    min_times = sys.maxsize

    for i in range(len_s[0]+1):

        for j in range(len_s[1]+1):

            for k in range(len_s[2]+1):

                sum = i*coins[0] + j*coins[1] + k*coins[2]
                times = i + j + k

                if sum == x and times < min_times:
                    min_times = times


    return min_times

使用动态规划,可以将复杂度将为O(m*n)。分析该问题时,将n暂且设为[2,5,7],m设为27.

要使用动态规划,首先需要确定状态:

     最后一步:最优策略中使用的最后一枚硬币a_{k},即有多少枚硬币,最后一步的最优策略就有多少种;

     将其优化成子问题:使用最好的硬币拼出更小的面值27-a_{k}

其次确定转移方程:

      f[x] = min{(f[x-2]+1,f[x-5]+1,f[x-7]+1)}

然后确定初始条件和边界情况:

    初始条件:f[0] = 0

    边界情况:如果n中的所有硬币组合都不能评出x(包括负数),则f[x] = { + \infty }

最后使用动态规划就是为了在计算下一项时可以直接已经计算的项,如f[8] = min(f[6]+1,f[3]+1,f[1]+1),此时f[6]已经计算过,此时就不需要重复计算,代码如下:

 

def coinChange(self, coin_list, tg_num):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
         # 最大值变量
        import sys
        max_v = sys.maxsize

        # 创建一个数组,保存计算的值
        funcs = [None]*(tg_num+1)

        # 初始条件
        funcs[0] = 0

        # 依次从小到大计算
        for s_v in range(1,tg_num+1):
            funcs[s_v] = max_v
            # 实现转移方程
            for coin_v in coin_list:

                # 设定边界条件
                if s_v >= coin_v and funcs[s_v-coin_v] != max_v:

                    funcs[s_v] = min(funcs[s_v-coin_v]+1,funcs[s_v])

        # 如果计算的值仍然是极大值,直接返回-1
        if funcs[tg_num]  == max_v:return -1

        return funcs[tg_num]

动态规划在解决求解极值问题时是一种很有意思的算法,只要按步骤定义好状态、转移方程和边界,就可以一步步完成,谨以此记录。  

解决该问题时,动态规划参考了九章算法。

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值