コイン交換のアルゴリズム-01

1.何かを言う

アルゴリズム、アルゴリズム、アルゴリズムは常に存在します。LinLinは常に、小さなものが200あると言っており、私はいくつかの記事や本を読みました。
コインの交換を見て、私はまだ何もできませんでした。
あなたはあなたの思考と学習の状態を変えなければなりません。

  1. 質問ごとに、さまざまな解決策と時間と空間の複雑さを書く必要があります。
  2. 必ず要約を書いてください、これは非常に重要です!

2.タイトルの説明

この問題は私たちの日常生活でより一般的です。1元、2元、5元、10元、20元、50元、100元の紙幣があるとします。紙幣の数は、それぞれc1、c2、c5、c10、c20、c50、c100です。このお金を使ってK元を支払います。使用する必要のある紙幣の最低額はいくらですか。

3.まとめ

3.1問題解決のアイデア

  1. 貪欲:額面が最も大きいものを探し、それが十分でない場合は下に移動します。ローカルソリューションは最適なソリューションではないため、すべての値を列挙することが本当の答えです(つまり、バックトラッキング方法、すべての答えを使い果たします)
  2. 動的計画法:1枚の紙幣の最大量はいくつですか。2枚の紙幣の最大量は、再帰の量よりも少なくなります。

3.2まとめ

  1. 貪欲は機能しません。
  2. バックトラックを実行できます。
  3. 動的計画法には、1次元配列と2次元配列の2つのソリューションがあり、1次元配列には2つのソリューションがあります。
  4. 再帰には、再帰と再帰的回想録の2つの解決策があります。
  5. バックトラックと再帰は解決策ですが、一方は考えられ、もう一方は実現です。
  6. 6つのソリューションと7つの実現があります。
  7. 7番目の実現、最高。

4.解決策

4.0欲張りアルゴリズム

時間:指数レベル。
スペース:O(n)(再帰的なn番目のスペース)

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バックトラック(激しい疲労)(剪定された4.2再帰)

時間:指数レベル。
スペース:O(n)(再帰的なn番目のスペース)

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再帰(動的計画法-ツリー形式)

時間計算量:指数レベル(sだけでなく、s-1およびs-2の指数にも関連)
空間計算量:O(s)(再帰的空間メモリ)

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再帰+回想録(再帰的最適化)

時間計算量:O(sn)
空間計算量: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動的計画法+2次元配列

これは最も基本的な動的計画法アルゴリズムです。
時間計算量O(s s n)
空間計算量: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動的計画法+1次元配列

時間計算量:O(sn)
空間計算量:O(s)

思路:dp [i] = min(dp [ix]、dp [iy])+ 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動的計画法+1次元配列(最適化)

時間計算量:O(sn)
空間計算量: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]
}

おすすめ

転載: blog.csdn.net/a519991963/article/details/112271485