Algorithm of Coin Change-01

1. Say something

There are always algorithms, algorithms, algorithms. Lin Lin always said that there are two hundred small ones, and I have read a few articles and books.
Seeing the coin change, I was still unable to do anything.
You have to change your thinking and state of learning.

  1. For each question, various solutions and time and space complexity should be written.
  2. Be sure to write a summary, this is very important!

2. Title description

This problem is more common in our daily lives. Suppose we have banknotes of 1 yuan, 2 yuan, 5 yuan, 10 yuan, 20 yuan, 50 yuan, and 100 yuan. The numbers of them are c1, c2, c5, c10, c20, c50, and c100, respectively. We are now going to use this money to pay K yuan. What is the minimum amount of banknotes we need to use?

3. Summary

3.1 Problem-solving ideas

  1. Greedy: Look for the one with the largest face value, and then go down when it is not enough. The local solution is not the optimal solution, so it is the real answer to enumerate all the values ​​(that is, the backtracking method, exhaust all the answers)
  2. Dynamic planning: What is the maximum amount of one banknote, and the maximum amount of two banknotes is less than the amount, recursively. .

3.2 Summary

  1. Greedy doesn't work.
  2. Backtracking can be done.
  3. Dynamic programming has two solutions, one-dimensional array and two-dimensional array, and one-dimensional array has two solutions.
  4. Recursion has two solutions: recursion and recursive memoirs.
  5. Backtracking and recursion is a solution, but one is thought and the other is realization.
  6. There are six solutions and seven realizations.
  7. The seventh realization, the best.

4. Solution

4.0 Greedy Algorithm

Time: Exponential level.
Space: O(n) (recursive n-th space)

let coinChange = function (coins, amount, idxCoin = 0) {
    coins = coins.sort((a, b) => b - a) // 排序

    return _c(coins, amount, idxCoin)
}

let _c = function (arr, amount, count = 0) {
    if (amount < 0) {
        return -1;
    }

    if (amount === 0) {
        return count;
    }

    for (var i = 0; i < arr.length; i++) {
        let max = Math.floor(amount / arr[i]);

        for (var j = max; j > 0; j--) {
            let res = _c(arr, amount - j * arr[i], j + count)
            if (res !== -1) {
                return res
            }
        }
    }

    return -1;
}

4.1 Backtracking (violent exhaustion) (pruned 4.2 recursion)

Time: Exponential level.
Space: O(n) (recursive n-th space)

let coinChange = function (coins, amount,idxCoin=0) {
    return _c(coins, amount, idxCoin)
}

let _c = function(coins, amount, idxCoin){
        if (amount === 0) {
        return 0;
    }

    if (idxCoin < coins.length && amount > 0) {
        let maxVal = Math.round(amount / coins[idxCoin]);
        let minCost = Number.MAX_SAFE_INTEGER;
        for (let x = 0; x <= maxVal; x++) {
            if (amount >= x * coins[idxCoin]) {
                let res = _c(coins, amount - x * coins[idxCoin],idxCoin + 1);
                if (res !== -1) {
                    minCost = Math.min(minCost, res + x)
                }
            }
        }

        return (minCost === Number.MAX_SAFE_INTEGER) ? -1 : minCost
    }

    return -1;
}

4.2 Recursion (dynamic programming-tree form)

Time complexity: Exponential level (not only related to s, but also related to the exponents of s-1 and s-2)
Space complexity: O(s) (recursive spatial memory)

let coinChange = (coins, amount) => {
    if (amount < 1) {
        return 0;
    }

    return _coin(coins, amount)
}

let _coin = (coins, amount) => {
    console.log(amount)
    if (amount < 0) {
        return -1;
    }

    if (amount === 0) {
        return 0
    }

    let min = Number.MAX_SAFE_INTEGER;
    for (let coin of coins) {
        let res = _coin(coins, amount - coin);
        if (res >= 0 && res < min) {
            min = res + 1;
        }
    }

    return min === Number.MAX_SAFE_INTEGER ? -1 : min;
}

4.3 Recursion + Memoir (recursive optimization)

Time complexity: O(sn)
Space complexity: O(S)

let coinChange = (coins, amount) => {
    if (amount < 1) {
        return 0
    }

    return _coin(coins, amount, new Array(amount).fill(0))
}

let _coin = (coins, amount, count) => {
    if (amount < 0) {
        return -1;
    }

    if (amount === 0) {
        return 0;
    }

    if (count[amount - 1] !== 0) {
        return count[amount - 1]
    }

    let min = Number.MAX_SAFE_INTEGER;
    for (let coin of coins) {
        let res = _coin(coins, amount - coin, count);
        if (res >= 0 && res < min) {
            min = res + 1;
        }
    }

    count[amount - 1] = (min === Number.MAX_SAFE_INTEGER) ? -1 : min;
    return count[amount - 1]
}

4.4 Dynamic programming + two-dimensional array

This is the most basic dynamic programming algorithm.
Time complexity O(s s n)
Space complexity: O(sn)

var coinChange = function(coins, amount) {
  if(amount === 0){
    return 0;
  }

  let n = amount+1;
  let dp = new Array(amount+1).fill(new Array(amount+1).fill(0));

  for(let i = 0; i < coins.length; i++){
    dp[0][coins[i]] = 1;
  }

  if(dp[0][n-1]){
    return 1;
  }

  for(let i = 1; i < n; i++){
    for(let j = n-1; j>=1; j--){
      dp[i][j] = dp[i-1][j];

      for(let m = 0; m < coins.length; m++){
        if(j + coins[m] <= amount && dp[i][j]){
          dp[i][j+coins[m]] = 1; 
        }
      }
    }

    if(dp[i][n-1]){
      return i+1;
    }
  }

  return -1;
};

4.5 Dynamic programming + one-dimensional array

Time complexity: O(sn)
Space complexity: O(s)

思路: dp[i] = min(dp[i-x],dp[i-y]) + 1;

var coinChange = function (coins, amount) {
    let dp = new Array(amount + 1).fill(Infinity);
    dp[0] = 0;

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

    return dp[amount] === Infinity ? -1 : dp[amount];
}

4.6 Dynamic programming + one-dimensional array (optimization)

Time complexity: O(sn)
Space complexity: O(s)

const coinChange = (coins, amount) => {
    let dp = new Array(amount + 1).fill(Number.MAX_SAFE_INTEGER);
    dp[0] = 0;
    for (let coin of coins) {
        for (let i = coin; i <= amount; i++) {
            dp[i] = Math.min(dp[i], dp[i - coin] + 1)
        }
    }
    return dp[amount] === Number.MAX_SAFE_INTEGER ? -1 : dp[amount]
}

Guess you like

Origin blog.csdn.net/a519991963/article/details/112271485