admin管理员组文章数量:1208153
The problem goes like this:
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1
Here's how I try to solve. But it fails for this test case: [195,265,404,396], amount 3239
Where am I going wrong? Appreciate any help.
var coinChange = function(coins, amount) {
let ans = Infinity;
var helper = function(coins, amount, index=0, coinsNeeded = 0){
if(amount === 0){
ans = Math.min(ans, coinsNeeded);
return;
}
if(index >= coins.length) return;
if(coins[index] > amount) return;
if(amount % coins[index] === 0){
ans = Math.min(ans, coinsNeeded + amount / coins[index]);
}
helper(coins, amount-coins[index], index, coinsNeeded+1);
helper(coins, amount, index+1, coinsNeeded);
}
helper(coins, amount);
return ans === Infinity ? -1 : ans;
};
console.log(coinChange([1,2,5], 11))
The problem goes like this:
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1
Here's how I try to solve. But it fails for this test case: [195,265,404,396], amount 3239
Where am I going wrong? Appreciate any help.
var coinChange = function(coins, amount) {
let ans = Infinity;
var helper = function(coins, amount, index=0, coinsNeeded = 0){
if(amount === 0){
ans = Math.min(ans, coinsNeeded);
return;
}
if(index >= coins.length) return;
if(coins[index] > amount) return;
if(amount % coins[index] === 0){
ans = Math.min(ans, coinsNeeded + amount / coins[index]);
}
helper(coins, amount-coins[index], index, coinsNeeded+1);
helper(coins, amount, index+1, coinsNeeded);
}
helper(coins, amount);
return ans === Infinity ? -1 : ans;
};
console.log(coinChange([1,2,5], 11))
Share
Improve this question
edited Jan 19 at 12:31
ABGR
asked Jan 19 at 9:52
ABGRABGR
5,2054 gold badges31 silver badges55 bronze badges
11
- [195,265,404,396], amount 3239 should fail as in return -1. 3239/396 = 8 with 71 remainder but there's combination of coins that divide into 71 so the return is -1. See my answer – zer00ne Commented Jan 19 at 11:54
- Well, even I"m getting -1 for this case. However, the correct answer supposedly is 12 for the above case. @zer00ne – ABGR Commented Jan 19 at 12:08
- Explain how it is 12. My logic isn't gisting with the question? – zer00ne Commented Jan 19 at 12:12
- @zer00ne That's precisely my confusion as well. But as per the test case on leetcode, this should be 12. See the Pic. Also here: leetcode.com/problems/coin-change/submissions/1513521034 – ABGR Commented Jan 19 at 12:26
- 1 I see glad you got it, happy coding. – zer00ne Commented Jan 19 at 16:55
3 Answers
Reset to default 2So the issue here was this line:
if(coins[index] > amount) return;
It obviously works for most cases and the intention was to return when the amount is greater than the value at that index. However, it wouldn't work for say [20, 6]
and 26
and it would return Infinity.
So the solution is to remove this check and instead apply it where we're taking the item:
if(coins[index] <= amount) helper(coins, amount-coins[index], index, coinsNeeded+1);
var coinChange = function(coins, amount) {
let ans = Infinity;
var helper = function(coins, amount, index=0, coinsNeeded = 0){
if(amount === 0){
ans = Math.min(ans, coinsNeeded);
return;
}
if(index >= coins.length) return;
if(amount % coins[index] === 0){
ans = Math.min(ans, coinsNeeded + amount / coins[index]);
}
if(coins[index] <= amount) helper(coins, amount-coins[index], index, coinsNeeded+1);
helper(coins, amount, index+1, coinsNeeded);
}
helper(coins, amount);
return ans === Infinity ? -1 : ans;
};
console.log(coinChange([20, 6], 26));
console.log(coinChange([195,265,404,396], 3239))
I am not sure what are you doing wrong, but maybe this helps a bit. The easiest way (assuming there are no performance requirements) is to calculate the number of coins needed for ever amount up to the requested one. In your case, from 0 to 3239. Next step would be to iterate over the given amounts and for each calculate the minimum. For given amount you iterate over given coins and try to subtract that coin from amount and if the result is greater than -1, then you know that solution for amount subtracted by current coin value could be increased by 1 coin. But before persisting this number, you have to check if we already have a number for that amount and persist new number only if it is smaller (since we are looking for least amount of coins).
function coinChange(coins, amount) {
// Initialize minCoinsForAmoint array with a large value (infinity)
let minCoinsForAmoint = new Array(amount + 1).fill(Infinity);
minCoinsForAmoint[0] = 0; // Base case: 0 coins to make amount 0
// Iterate over all amounts from 1 to the target amount
for (let i = 1; i <= amount; i++) {
// Try using each coin to update minCoinsForAmoint[i]
for (let coin of coins) {
if (i - coin >= 0) {
minCoinsForAmoint[i] = Math.min(minCoinsForAmoint[i], minCoinsForAmoint[i - coin] + 1);
}
}
}
// If minCoinsForAmoint[amount] is still infinity, it means it's impossible to form that amount
return minCoinsForAmoint[amount] === Infinity ? -1 : minCoinsForAmoint[amount];
}
const coins = [195,265,404,396];
const amount = 3239;
console.log(coinChange(coins, amount));
Edit: in case you are more interested in background and details of this mathematical coin change problem, check Wikipedia: Change-making problem
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignment, and other side effects. We can use a straightforward inductive strategy.
- (base) if amount is zero, the goal has been reached, return the empty sum,
0
- (inductive) the amount is non-zero. If there are no coins or the amount is negative, return the out-of-bounds result,
-1
- (inductive) there is at least one coin and the amount is greater than zero. Compute the result of using the first coin, increment it, and compute the result of skipping this coin. Return the minimum of both results.
function change(coins, amount) {
if (amount == 0) return 0 // 1️⃣
if (coins[0] == null || amount < 0) return -1 // 2️⃣
return min( // 3️⃣
inc(change(coins, amount - coins[0])),
change(coins.slice(1), amount)
)
}
function min(a, b) {
if (a == -1) return b
if (b == -1) return a
return Math.min(a, b)
}
function inc(a) {
return a == -1 ? -1 : a + 1
}
console.log(change([20, 6], 26)) // => 2
console.log(change([195,265,404,396], 3239)) // => 12
The -1
is the hard part of the assignment because it conflicts with "minimum" output of your main function. -1
is less than all valid return values, so using Math.min
directly will not work. My suggestion is to use helpers like min
and inc
to work with the out-of-bounds -1
values and avoid this complexity in your main function.
本文标签: algorithmCoin changeA test case is failingStack Overflow
版权声明:本文标题:algorithm - Coin change - A test case is failing - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738742615a2109939.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论