【问题标题】:Least number of coins needed using a Hash Map (Timing Out)使用哈希映射所需的最少硬币数量(超时)
【发布时间】:2021-11-09 08:58:09
【问题描述】:

我正在编写一个函数来查找进行一定数量的零钱所需的最少硬币数量。 See this problem

这是一个动态编程问题,但是,我没有使用传统的数组,而是尝试使用一个对象来记忆结果。它叫coinAmounts

该地图包含一个由最少数量的硬币组成的数组以产生特定的总和,例如,要产生 6 的数量,您需要 [5,1]。

我有一个 getCoinsToMakeAmountsetCoinsToMakeAmount 来编辑/获取地图中的值。当我们迭代路径时,setCoins 将更新我们的地图,如果我们通过它的路径是一个较小的硬币组合以获得给定的总和。

基本方法是回溯算法,然后我使用coinMap 来记忆总和。

编辑

我相信我错过了优化,因为该算法似乎适用于较小的循环,但是对于这样的较大输入,它似乎不是很好。

coins = [3,7,405,436]
sum = 8839
let combos = []

let coinAmounts = {}

let cycles = 0;

/**
 * @param {number[]} coins
 * @param {number} amount
 * @return {number}
 */
var coinChange = function(coins, amount) {
    coinAmounts = {}
    combos = []
    
    if(amount === 0) return 0;
    
    coinChangeHelper(coins, 0, [], amount,0);
     console.log(coinAmounts)
    //console.log(combos);
    // console.log("CYCLES: " + cycles)
    if(!coinAmounts[amount]) return -1;
    return coinAmounts[amount].length;
};


var coinChangeHelper = function(coins, amount, _chosen, desiredAmount, minPath){
    let chosen = Object.assign([], _chosen);   
    cycles++;
    
    // save the current iteration if it's better
    setLowestCoinsToMakeAmount(amount, chosen); 
    
    if(amount > desiredAmount){
        return false;
    }
   
    if(amount === desiredAmount){
        combos.push(chosen);
        return true;
    }
    
    // see if we already know how to make the amount requested
    // need to do something with this chosen coins
    const chosenCoins = getCoinsToMakeAmount(amount);
    
    if(chosenCoins && chosenCoins.length < chosen.length){
        return true;
    }
    
    
     //debug(coins, amount, chosenCoins, _chosen)
    
    // like a backtracking algo
    for(let i = minPath; i<coins.length; i++){
        const coinAmount = coins[i];
   
        // choose a coin
        chosen.push(coinAmount)
        
        coinChangeHelper(coins,amount+coinAmount, chosen, desiredAmount, i);
        
        // unchoose the coin
        chosen.pop(); 
    }
    
}

// get a coin value
const getCoinsToMakeAmount = (amount, startCoin) => {
    const currentCoinCount = coinAmounts[amount];
    if(!currentCoinCount){
        return undefined;
    }

    return currentCoinCount;
}


const setLowestCoinsToMakeAmount = (coinsSum, coinsChosen) =>{
    if(coinsChosen.length <= 0) return;
    const currentCoinCount = coinAmounts[coinsSum];
    if(!currentCoinCount){
         coinAmounts[coinsSum] = coinsChosen;   
         return;
    }
    
    if(coinsChosen.length < currentCoinCount.length){
     coinAmounts[coinsSum] = coinsChosen;   
    }
}
 

// nicely print out the output
var debug = (coins, amt, memo, chosen) => {
    let tabs = ''
    for(let i =0; i<amt; i++){
         tabs = tabs+'\t';
    }
    console.log(`${tabs} change([${amt}], [${memo}],[${chosen}]`)
}

对于 (coins=[1,2,5], amount=11) 的情况,coinAmounts 包含最佳硬币数量以达到一定的总和。

{
  '1': [ 1 ],
  '2': [ 2 ],
  '3': [ 1, 2 ],
  '4': [ 2, 2 ],
  '5': [ 5 ],
  '6': [ 1, 5 ],
  '7': [ 2, 5 ],
  '8': [ 1, 2, 5 ],
  '9': [ 2, 2, 5 ],
  '10': [ 5, 5 ],
  '11': [ 1, 5, 5 ],
  '12': [ 2, 5, 5 ],
  '13': [ 1, 2, 5, 5 ],
  '14': [ 2, 2, 5, 5 ],
  '15': [ 5, 5, 5 ]
}

【问题讨论】:

    标签: javascript dynamic-programming backtracking recursive-backtracking


    【解决方案1】:

    我相信您可以在简化方法的同时提高算法的准确性。创建getCoins 函数,我们首先对可用硬币进行排序。然后我们循环,得到小于或等于剩余总数的最高硬币数量,直到它为零:

    function getCoins(coins, amount) {
        coins.sort((a,b) => b - a);
        const result = [];
        while (amount > 0) {
            let nextCoin = coins.find(coin => coin <= amount);
            if (nextCoin) {; 
                result.push(nextCoin);
                amount -= nextCoin;
            }
        }
        return result;
    }
    
    let length = 10;
    const coins = [1,2,5];
    for(let amount = 1; amount <= 20; amount++) { 
        console.log(`Amount: ${amount}, Coins:`, JSON.stringify(getCoins(coins, amount)));
    }

    【讨论】:

    • 我不太清楚 Array.From 行发生了什么?假设我想调整这个算法以获得匹配的确切硬币,这将如何使用这种方法?
    • Array.from 行只是为了演示 1 到 10 的数量的结果。函数根本不需要。要获得最少的硬币数量,只需使用可能的硬币数组和目标数量调用 getCoins。
    • getCoins() 函数将准确匹配的硬币作为数组返回。
    • 我想我仍在寻找它是否可以与哈希映射一起使用,类似于这种方法。我想看看它是否可以使用像上面这样的回溯方法。 :leetcode.com/problems/coin-change/discuss/77378/…
    • 啊,是的,这是一个有趣的方法。
    猜你喜欢
    • 2020-05-09
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    相关资源
    最近更新 更多