322. Coin Change

brute force

recursive like a tree, then do BFS, find the level which can subtract to 0 (11 -1 - 5 - 5 = 0

time: O(n^k), k is coins type

DFS + memo (top down)

T: O(kn)

S: O(n)

class Solution {
    public int coinChange(int[] coins, int amount) {
        return dfs(coins, amount, new Integer[amount+1]);
    }
    private int dfs(int[] coins, int amount, Integer[] memo) {
        if (amount == 0) { // no more amount, should return 0
            return 0;
        }
        if (amount < 0) {
            return -1;
        }
        if (memo[amount] != null) {
            return memo[amount];
        }
        int result = Integer.MAX_VALUE;
        for (int coin : coins) {
            int numbers = dfs(coins, amount - coin, memo);
            if (numbers == -1) {
                continue;
            }
            result = Math.min(result, 1 + numbers);
        }
        return memo[amount] = (result == Integer.MAX_VALUE ? -1 : result);
    }
}

class Solution {
    public int coinChange(int[] coins, int amount) {
        return dp(coins, amount, new Integer[amount+1]);
    }
    private int dp(int[] coins, int amount, Integer[] memo) {
        if (amount == 0) {
            return 0;
        }
        if (amount < 0) {
            return -1;
        }
        if (memo[amount] != null) {
            return memo[amount];
        }
        int result = Integer.MAX_VALUE;
        for (int coin : coins) {
            int sub = dp(coins, amount - coin, memo);
            if (sub == -1) { // key point!
                continue;
            }
            result = Math.min(result, sub + 1);
        }
        return memo[amount] = (result != Integer.MAX_VALUE ? result: -1);
    }
    
}

// thought -> 
/*
fewest number of coins
subproblem -> f(10), f(9), f(6) , these are all dependent
f(11) = f(10) + 1 (if choose 1)
f(11) = f(9) + 1 (if choose 2)
f(11) = f(6) + 1 (if choose 5)

   f(11)
   /    
   f(10)  9.  6
   / \\    /
   9 8 5  8
   
k : how many kind of coins type
k^n , n subproblems
*/

// use memo -> k^n to k*n

   
   

DP (bottom up

ๆœ‰ๅนพ็จฎ็กฌๅนฃ, ็ต„ๆˆ amount => ๆ˜ฏไธๆ˜ฏๅพˆๅƒ็ˆฌๆจ“ๆขฏๅ•้กŒ

subproblem & dp array:

f(n) = min ( f(n-k) ), for k in [1,2,3]) + 1

time: O(kn), n: amount, k: coins' number, O(n)

space: O(n), n: amount

class Solution {
    public int coinChange(int[] coins, int amount) {
        int dp[] = new int[amount+1]; // ๅˆๅง‹็ตๆžœ้ƒฝๆ˜ฏamount+1
        Arrays.fill(dp, amount+1);
        dp[0] = 0;
        for (int i = 0; i < amount+1; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (i - coins[j] >= 0) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return (dp[amount] > amount) ? -1 : dp[amount]; 
        // ๅˆๅง‹amount+1,ๆ‰€ไปฅๅฆ‚ๆžœๆฏ” amount ๅคง, ไปฃ่กจๆฒ’ๆ‰พๅˆฐ
    }
}

็•ถๅ‰ๅกซๆปฟๅฎน้‡ dp[i] ๆœ€ๅฐ‘้œ€่ฆ็š„็กฌๅนฃ =

min(ไน‹ๅ‰ๅกซๆปฟๅฎน้‡ dp[i] ๆœ€ๅฐ‘้œ€่ฆ็š„็กฌๅนฃ , ๅกซๆปฟๅฎน้‡ dp[i - coin ้œ€่ฆ็š„็กฌๅนฃ + 1ๅ€‹็•ถๅ‰็กฌๅนฃ] . ๏ผ‰

for loop ๅŽป่ฎŠๆ› coin ้œ€่ฆ็š„็กฌๅนฃ, f(n) = min ( f(n-k) ), for k in [1,2,3]) + 1

ๅ› ็‚บๆ˜ฏๅคšๅ€‹ f(n-k) ่ฆๆ‰พๆœ€ๅฐ,

ๆ‰€ไปฅๅœจ dp[i] ๅ–ๅพ—ๅ€ผ, ่ฆ Math.min(dp[i], dp[i-coins[j]+1)

Math.min(dp[i] . => ไปฃ่กจไน‹ๅ‰ Math.min(dp[i], dp[i-coins[j]+1) => dp[i-coins[j]+1็ฎ—ๅ‡บ็š„็ตๆžœ

        for (int i = 0; i < amount+1; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (i - coins[j] >= 0) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }

new version

class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount+1];
        Arrays.fill(dp, amount + 1);
        
        dp[0] = 0;
        
        for (int i = 0; i < dp.length; i++) {
            for (int coin : coins) {
                if (i - coin >= 0) {
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }
        return dp[amount] != amount + 1 ? dp[amount] : -1;
    }
}

Last updated