再学动态规划之 完全背包

LeetCode: https://leetcode.com/problems/coin-change/description/
在这里插入图片描述

暴力搜索

考虑当前index 拿1张,2张,…时候,从index+1开始的最小张数。相加即可:

import sys
class Solution(object):

    def get_small_number(self, coins, index, amount):
        if amount == 0:
            return 0
        if amount < 0:
            return -1
        if index == len(coins)-1:
            if amount%coins[index] != 0:
                return -1
            else:
                return amount/coins[index]
        min_res = sys.maxint
        for i in range(amount/coins[index] + 1):
            back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
            this_amount = back_amount + i
            if back_amount == -1:
                this_amount = sys.maxint
            min_res = min(min_res, this_amount)
        return min_res

    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        return -1 if self.get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)

记忆化搜索

当前的问题就是,每次都没有把结果记录下来,导致重复计算。故 超时
比如[1 ,2, 5] 目标是 11 的时候。1拿2张,2拿0张 和 1拿0张,2拿1张;应该是一种情况。

import sys
res = dict()
class Solution(object):

    def get_small_number(self, coins, index, amount):
        if amount == 0:
            return 0
        if amount < 0:
            return -1
        if index == len(coins)-1:
            if amount%coins[index] != 0:
                return -1
            else:
                return amount/coins[index]
        if str(index)+'_'+str(amount) in res:
            return res[str(index)+'_'+str(amount)]
        min_res = sys.maxint
        for i in range(amount/coins[index] + 1):
            back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
            this_amount = back_amount + i
            if back_amount == -1:
                this_amount = sys.maxint
            min_res = min(min_res, this_amount)
        res[str(index)+'_'+str(amount)] = min_res
        return min_res


    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        res.clear()
        return -1 if self.get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)

这次记忆化搜索都超时了诶。。。

动态规划

状态转移方程式:
d p [ i ] [ j ] = m i n t ∈ [ 0 , 1 + j / c o i n s ] { t + d p [ i − 1 ] [ j − c o i n s [ i ] ∗ t ] } dp[i][j]=min_{t\in[0,1+j/coins]}\{t+dp[i-1][j-coins[i]*t]\} dp[i][j]=mint[0,1+j/coins]{t+dp[i1][jcoins[i]t]}

import sys
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
        for ix in range(len(coins)+1):
            arr[ix][0] = 0
        for i in range(1, len(coins)+1):
            for j in range(1, amount+1):
                res_min = arr[i-1][j]
                for t in range(1, j/coins[i-1]+1):
                    res_min = min(res_min, t+arr[i-1][j-coins[i-1]*t])
                arr[i][j] = res_min


        return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]

依然超时呢。还有什么优化空间吗?
我把递推公式展开来写,你就会发现所谓的优化空间了;
d p [ i ] [ j ] = m i n { d p [ i − 1 ] [ j ] , 1 + d p [ i − 1 ] [ j − x ] , 2 + d p [ i − 1 ] [ j − 2 x ] + . . . } dp[i][j] = min\{dp[i-1][j],1+dp[i-1][j-x],2+dp[i-1][j-2x]+...\} dp[i][j]=min{dp[i1][j],1+dp[i1][jx],2+dp[i1][j2x]+...}
d p [ i ] [ j − x ] = m i n { d p [ i − 1 ] [ j − x ] , 1 + d p [ i − 1 ] [ j − 2 x ] , 2 + d p [ i − 1 ] [ j − 3 x ] + . . . } dp[i][j-x] =min\{dp[i-1][j-x],1+dp[i-1][j-2x],2+dp[i-1][j-3x]+...\} dp[i][jx]=min{dp[i1][jx],1+dp[i1][j2x],2+dp[i1][j3x]+...}
所以:
d p [ i ] [ j ] = m i n { d p [ i − 1 ] [ j ] , 1 + d p [ i ] [ j − x ] } dp[i][j] = min\{dp[i-1][j],1+dp[i][j-x]\} dp[i][j]=min{dp[i1][j],1+dp[i][jx]}

import sys
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
        for ix in range(len(coins)+1):
            arr[ix][0] = 0
        # arr[:][0] = 1
        for i in range(1, len(coins)+1):
            for j in range(1, amount+1):
                res_min = arr[i-1][j]
                if j - coins[i-1] >= 0:
                    res_min = min(res_min, 1+arr[i][j-coins[i-1]])
                arr[i][j] = res_min
        return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值