1.何かを言う
アルゴリズム、アルゴリズム、アルゴリズムは常に存在します。LinLinは常に、小さなものが200あると言っており、私はいくつかの記事や本を読みました。
コインの交換を見て、私はまだ何もできませんでした。
あなたはあなたの思考と学習の状態を変えなければなりません。
- 質問ごとに、さまざまな解決策と時間と空間の複雑さを書く必要があります。
- 必ず要約を書いてください、これは非常に重要です!
2.タイトルの説明
この問題は私たちの日常生活でより一般的です。1元、2元、5元、10元、20元、50元、100元の紙幣があるとします。紙幣の数は、それぞれc1、c2、c5、c10、c20、c50、c100です。このお金を使ってK元を支払います。使用する必要のある紙幣の最低額はいくらですか。
3.まとめ
3.1問題解決のアイデア
- 貪欲:額面が最も大きいものを探し、それが十分でない場合は下に移動します。ローカルソリューションは最適なソリューションではないため、すべての値を列挙することが本当の答えです(つまり、バックトラッキング方法、すべての答えを使い果たします)
- 動的計画法:1枚の紙幣の最大量はいくつですか。2枚の紙幣の最大量は、再帰の量よりも少なくなります。。
3.2まとめ
- 貪欲は機能しません。
- バックトラックを実行できます。
- 動的計画法には、1次元配列と2次元配列の2つのソリューションがあり、1次元配列には2つのソリューションがあります。
- 再帰には、再帰と再帰的回想録の2つの解決策があります。
- バックトラックと再帰は解決策ですが、一方は考えられ、もう一方は実現です。
- 6つのソリューションと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]
}