(leetcode322) Change exchange (greedy+dfs, top-down and bottom-up of dynamic programming)

The original title of leetcode, as shown in the figure:
Insert picture description here

1. Greedy + dfs

The author's first idea is to get all the combinations of the sum of the values, take the shortest combination length and return, or return -1 if there is none.
Based on this idea, the author did a depth-first traversal of dfs.
The initial timeout is always due to insufficient pruning. The final code is:

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        if amount==0:
            return 0
        coins.sort()
        global ret
        ret=float("inf")
        def dfs(n,target,big):
            #print(n,target,big)
            global ret
            #剪枝1,target比最小的面值还小,直接返回
            if target<coins[0]:
                return
            #得到一种组合,更新ret
            if target in coins:
                ret=min(ret,n+1)
                return
            for index in range(big,-1,-1):
            	#剪枝2,最大次数*最大面值<target,直接返回
                if (ret-n)*coins[index]<target:
                    break
                #剪枝3,本次面值大于target,因为coins排序后单调递减,进入下一面值即可
                if coins[index]>target:
                    continue
                else:
                	#直接dfs
                    dfs(n+1,target-coins[index],index)
        dfs(0,amount,len(coins)-1)
        if ret!=float("inf"):
            return ret
        else:
            return -1

Among them, the most important pruning is here:

				if (ret-n)*coins[index]<target:
                    break

That is, when the current maximum possible number of times (ret-n), multiplied by the maximum denomination (coins[index], because it is from large to small) cannot meet the condition and break directly.
Add this sentence before the timeout, plus more than 97.6% of the submissions afterwards, yes, it is so abnormal.

In addition, when looking at the solution, I learned the way to express the maximum value and the minimum value in python:

max_int=float("inf")
min_int=float("-inf")

2. Dynamic planning

These are the two dynamic programming methods given in the official solution:
top-down and bottom-up.
Original link The
state transition equation is: dp[n]=dp[n-coin]+1

(1) Top-down

The recursive process starts from the largest amount and gradually reduces coins.
Recursion exit:
(1) Less than 0 means when the upper recursion, the coin face value is greater than the target, return -1;
(2) When equal to 0 means the coin face value is equal to the target when the upper recursion, return 0, enter if in the upper recursion, and finally return it 1;
(3) If the mini value is not modified by subtracting all coins from for, it returns -1, which means that there is no coin combination in this layer to form the goal.
One very, very useful point here is

import functools
@functools.lru_cache(amount)

The author understands that it is a python decorator. The function of lru_cache is the result of temporarily storing the maximum amount. When the dp function is called again, it returns directly without entering the function again, thereby greatly reducing repeated calculations.

import functools
def coinChange(coins,amount):
        @functools.lru_cache(amount)
        def dp(rem):
            if rem < 0: return -1
            if rem == 0: return 0
            mini = int(1e9)
            for coin in coins:
                res = dp(rem - coin)
                if res >= 0 and res < mini:
                    mini = res + 1
            return mini if mini < int(1e9) else -1

        if amount < 1: return 0
        return dp(amount)

(2) Self-improvement

very clear.

def coinChange(coins,amount):
    dp=[float("inf")]*(amount+1)
    dp[0]=0
    for coin in coins:
        for index in range(coin,amount+1):
            dp[index]=min(dp[index],dp[index-coin]+1)

    return dp[amount] if dp[amount]<float("inf") else -1

Guess you like

Origin blog.csdn.net/qq_41584385/article/details/106006423