Coin Change

leetcode第332题,硬币找零,使用最少数量的指定硬币凑出目标数。
深度搜索,逐个加入硬币,当数额与目标数相等时,记录一下所用的硬币数,找出其中最小的就好了,但是这样做目标数很大的时候就会超时。

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """

        def dfs(current, coinNum, coinNumList, amount):
            if current == amount:
                coinNumList.append(coinNum)
                return
            if current > amount:
                return
            if current < amount:
                for coin in coins:
                    dfs(current+coin, coinNum+1, coinNumList, amount)

        coinNumList = []
        dfs(0, 0, coinNumList, amount)
        return min(coinNumList) if len(coinNumList) != 0 else -1

动态规划思路,dp[i]代表在第i个amount时需要最少的硬币数,状态转移方程为dp[i]=min(dp[i], dp[i-coins]+1)
具体操作就是,两层循环遍历,外层循环依次扫amount的可能取值,由1~amount,也就是遍历dp数组,然后遍历coin值,如果当前的amount比coin大,就有可能在当前的钱数里减去coin值,也就是说用这个币值去凑出这个数字,因此就是dp[i-coins]+1,这个数字和原来的dp[i]比,选取小的那个。
注意几个细节

  1. 初始化dp的时候,因为是要找最小值,所有我们dp一开始应该是最大的可能数字,也就是他本身,也就是只用面值1的硬币去凑。这里有一个小技巧,就是在此基础上各自在加1,原因间第3条
  2. dp[0]要初始化成0,代表0的时候的取值。
  3. 最后返回的时候检查一下dp[amount]和amount的大小,如果dp[amount] > amount,说明dp这个位置根本没有被修改过,还是原来的那个数,那个数是比当前amount还大1的数字,因此就说明不能凑出这样的amount,返回-1。
class Solution:
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        if amount == 0:
            return 0
        dp = [amount+1]*(amount+1)
        dp[0] = 0
        for i in range(1, amount+1):
            for coin in coins:
                 if coin <= i:
                    dp[i] = min(dp[i], dp[i-coin]+1)
        print(dp)
        return -1 if dp[amount] > amount else dp[amount]

你可能感兴趣的:(leetcode)