recursive function breaking in if statement javascript - javascript

i'm in the process of trying to write a function that converts an amount into a specified number of coins. For this I'm calling a function on itself (I think this is recursive programming?). I'm having 2 problems.
When i call the function on itself in the else section of the if statement I get the error message. "Maximum call stack size exceeded" ? Not sure why this is as the call above is the same and works fine when this second call is commented out.
Also when the second call is commented out and the function runs the variable total should be increasing by 1 with each call. However it doesn't make it past 1. I thought this may be because the variable was being reset at the top to 0 with each call. However the remainder variable is also set to 0 decreases its value each time.
Can anyone explain what is happening here ? How is this problem best solved ?
Thanks
function amountCoins(amt, coins) {
var remainder = 0;
total = 0;
if(amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(remainder, coins);
} else {
coins.shift();
//return amountCoins(remainder,coins);
}
alert(total);
}
amountCoins(121,[20,15,6,1]);

You can use .reduce() for this as an alternative.
And we don't really need loops where simple math can handle it.
var total = [20,15,6,1].reduce(function(obj, denomination) {
return {
total: obj.total + Math.floor(obj.amount / denomination),
amount: obj.amount % denomination
};
}, {amount:121, total:0}).total;
Or iterate the array.
var arr = [20,15,6,1], amount = 121, total = 0;
for (var i = 0; i < arr.length; ++i) {
total += Math.floor(amount / arr[i]);
amount %= arr[i];
}

I'd use a regular for loop instead, if I was you:
var amt = 121;
var coins = [20, 15, 6, 1];
var coinsUsed = {};
var totalCoins = 0;
for (var i = 0; i < coins.length; i++) {
if (coins[i] <= amt) {
coinsUsed[coins[i]] = Math.floor(amt / coins[i]);
amt -= coinsUsed[coins[i]] * coins[i];
totalCoins += coinsUsed[coins[i]];
} else {
coinsUsed[coins[i]] = 0;
}
}
console.log(coinsUsed, totalCoins);
Output:
Object {
1: 1,
6: 0,
15: 0,
20: 6
}
7

The problem is that your algorithm never ends. Every recursive function must have an end, if not it will produce a stack overflow (xD), because recursive calls are stored in a stack.
This would be a solution:
function amountCoins(amt, coins, total) {
var remainder = 0;
total = total || 0; //Default value 0 (for the first call)
if(coins.length == 0) return total; //This is the ending condition (no coins)
if(amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(remainder, coins, total);
} else {
coins.shift();
return amountCoins(remainder, coins, total);
}
}
var coins = amountCoins(121,[20,15,6,1]); //Returns: 6
alert(coins);
As you can see, I turned total into a param so we can store it from call to call.
Hope this helps. Cheers

i think this is what you are trying to do:
function amountCoins(amt, coins) {
var remainder = 0;
if(coins.length == 0) {
return 0;
} else if(amt >= coins[0]) {
remainder = (amt - coins[0]);
return amountCoins(remainder, coins)+1;
} else {
coins.shift();
return amountCoins(remainder,coins);
}
}
var total = amountCoins(121,[20,15,6,1]);
alert(total)
There are a few things here
A recursive algorithm needs a terminating condition. ie. when the function is calling itself recursively it should stop the chain at some point. If it doesnt, the program will run out of memory to accomodate all the calls in the chain. Because this is a potentially dangerous condition, programming languages like javascript limit the depth of a recursive call. This is what is meant by the Maximum call stack size exceeded error.
In your program, logically, the terminating condition is when we run out of coins. so a
coins.length == 0 check that returns a 0 total (which in turn seeds the upward chain) will fix the problem
Usually in recursive algorithms the result is passed backwards, up the call chain and not stored in an external variable. So the incrementing total value is expressed with a return statement like return amountCoins(remainder, coins)+1;
Finally, this problem can be much easily implemented with for loops. Try to think by unwinding the recursive call chains and you'll figure out a loop solution.

You must return total not only if no coins left, but also if the last coin's value is bigger then the remaining value:
function amountCoins(amt, coins, total) {
total = total || 0;
if (coins.length == 0 || (amt < coins[0] && coins.length == 1)) return total;
if (amt >= coins[0]) {
total += 1;
remainder = (amt - coins[0]);
return amountCoins(amt - coins[0], coins, total);
} else {
coins.shift();
return amountCoins(remainder, coins, total);
}
}

This correction to your original code will work:
function amountCoins(amt, coins, total) {
total = total || 0;
if (amt === 0) return total;
// throw out all the coins that are too big
while (amt < coins[0]) coins.shift();
// use the largest coin possible, then recurse
total += 1;
remainder = amt - coins[0];
return amountCoins(remainder, coins, total);
}
alert(amountCoins(121,[20,15,6,1])); // alerts 7
It has the advantage of avoiding unnecessary if ... else statements, and the logic is bit clearer imo

Related

Multiplicative Persistence program in Javascript not working

I can't get my program to work. The problem is a kata from Codewars:
Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
Example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
I've gone through answers to similar problems here already. This is my code:
var count = 0;
var product = 1;
function persistence(num) {
if (num.toString().length == 1) {
count+=0;
return count;
}
for (i of num.toString()) {
product *= Number(i);
}
count++;
var newProduct = product;
// reset product to 1 so that line ten does not
// start with the product from the last loop
product = 1;
persistence(newProduct);
}
I can't tell what the problem is. Initially I was getting a maximum call stack exceeded error. I researched that and realized I did this for my base case:
if (num.length == 1) {
count+=0;
return count;
}
instead of
if (num.toString().length == 1) {
count+=0;
return count;
}
My logic seems sound. What could the problem be?
Here's a much better way of solving your problem, complete with comments that I think gives a pretty clear explanation of what's going on.
function persistence(num) {
// Create a new function that you'll use inside your main function
function multiply(n) {
// Multiply the first number by next number in the array
// until the entire array has been iterated over
return n.reduce(function(a,b){return a*b;});
}
// Set the count to 0
var count =0;
// Use a while loop to iterate the same number of times
// as there are digits in num
while (num.toString().length > 1) {
// Splits the num into an array
num= num.toString().split("");
// Runs multiply on our num array and sets num to the returned
// value in preparation of the next loop.
// The multiply function will for 39 run 3 * 9 = 27,
// next iteration we've set num to 27 so multiply will be
// 2 * 7 = 14, then 1 * 4 = 4, and since num 4 now
// has a length <= 1 the loop stops.
num = multiply(num);
// Increase count by 1 each iteration, then run the next
// iteration in the loop with the new value for num being
// set to the result of the first multiplication.
count++;
}
return count; // return the value of count
}
console.log(persistence(39));// === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
console.log(persistence(999));// === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
console.log(persistence(4));// === 0 // because 4 is already a one-digit number
https://jsfiddle.net/8xmpnzng/
Use "of" instead of "in". "in" looks for properties. "of" increments an array.
var count = 0;
var product = 1;
function persistence(num) {
if (num.toString().length == 1) {
count+=0;
return count;
}
for (i of num.toString()) {
product *= Number(i);
}
count++;
var newProduct = product;
// reset product to 1 so that line ten does not
// start with the product from the last loop
product = 1;
persistence(newProduct);
}
I'm pretty sure it's this block:
for (i in num.toString()) {
product *= Number(i);
}
That's a for...in loop, which is used to iterate over keys in an object. If you want to multiply each digit of the num string together, you could split the string into an array, and use the reduce method (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce):
//this coerces the number into a string
const numString = num + ''
//this is the function to pass as the first argument into the reduce method
const multiplyAll = (accumulator, currentVal) => accumulator * Number(currentVal)
let product = numString.split('').reduce(multiplyAll, 1)
It's generally best practice to avoid declaring global variables outside of a function's scope, but you can do a cool trick with your recursion where you declare your count as a parameter in your function like so:
function persistence(num, count = 0) {
And then when you call it again with recursion, you simply add 1 like so:
function persistence(product, count + 1) {
Simpler way of Persistence:
let countIteration = 1;
function persistence(num) {
let numStr = num.toString();
if(numStr.toString().length === 1) {
return 0;
}
let numArr = numStr.split("");
let persistRes = numArr.reduce((acc, curr) => acc = curr * acc);
if (persistRes.toString().length !== 1) {
countIteration += 1;
return persistence(persistRes);
}
else {
return countIteration;
}
}
console.log(persistence(39)); // === 3
console.log(persistence(15)); // === 1
console.log(persistence(999));// === 4

Get factorial of all the numbers of array recursively

I am trying to get factorial of all the numbers of array(recurArray) using recursion and without loops.
I am getting Error "Maximum call stack size exceeded"
I think there is some issue with the for loop logic, would be helpful if someone can explain the cause of error and how to fix it
Thanks.
//code
function recur(){
var n;
var result;
if(n == 1)
return 1;
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
n = recurArray[i];
result = n * recur(n-1);
n=n-1;
}
console.log("val of n " + n + "value of i " + i);
return result;
}
recur();
Your recur() function should probably take n as an argument, otherwise n will never be 1 (if(n == 1) return 1;) and your function will keep calling itself until it crashes.
Try function recur(n){ instead.
As you have array, you should use loop.
function recur(x) {
if(x==0) {
return 1;
}
return x * recur(x-1);
}
function getFact() {
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
console.log(recur(recurArray[i]));
}
}
getFact();
In Each occurence you reset the factorial so it keep rolling for fact(5) you need to have a function that calculate the factorial and an other one for the loop over your array like this :
function recur(n){
if(n == 1){
return 1;
} else {
return n* recur(n-1);
}
}
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
n = recurArray[i];
result = recur(n);
console.log("factorial of n " + n + " is " + result);
}
Try something like this:
function factorial(number) {
var temp;
if(number <= 1) return 1;
temp = number * factorial(number - 1);
return temp;
}
In this case factorial(5); will return !5 . Recursive functions are not supposed to have loops inside(They can, but the execution time would be horrendous).
Also recursive functions call themselves with different parameters(otherwise you would overflow the browser stack). In your case you call recursive() an infinite amount of times and the loop always starts from 5 , infinitely. The passed parameter is what stops the recursion.

Javascript Factorialize returns incorrect result

Just wondering if anyone can tell me why this returns 100 and not 120? It should calculate the total number of the factor.
function factorialize(num) {
for(var i = 1; i <= num; i++ ) {
var fact = i+i;
total = fact * fact;
}
return total;
}
factorialize(5);
This is not the correct way to calculate the factorial. What is happening in your code is, the last time the line total = fact * fact; is run, fact has a value of 10 (because i is 5), so 10 * 10 becomes 100 and that is what it returns.
If you are trying to calculate the factorial, use this code:
function factorialize(num) {
var total = 1; // Initialize the total. 0! = 1.
for(var i = 1; i <= num; i++ ) {
total = total * i; // Add the current index to the factors by multiplying it by the current total.
}
return total;
}
TLDR is you're overwriting all the values of fact. var is scoped to a function in JS. Eventually you reach i = 5, which eventually sets fact to (5+5) * (5+5) which is 100.

Sum an array of numbers in Javascript using Recursion

Why isn't this working? I'm getting a stack too deep error:
var countRecursion = function(array) {
var sum = 0
var count = 0
sum += array[count]
count ++
if (count < array.length) {
countRecursion(array);
} else {
return sum
}
}
You made a mistake and reset sum and counter inside the recursive block. I simply moved them outside.
var countRecursion = function(array) {
sum += array[count]
count ++
if (count < array.length) {
countRecursion(array);
} else {
return sum
}
}
var sum = 0
var count = 0
countRecursion([1,2,3]);
alert(sum);
This code is not recursive but iterative. I am not 100% sure if that's what you really wanted. But since you mentioned it, some people down voted my answer since I only fixed your code, but didn't made it recursive I guess. For completeness, here is recursive version of your code:
var countRecursion = function(array, ind) {
if (ind < array.length) {
return array[ind] + countRecursion(array, ind + 1);
} else {
return 0;
}
}
var sum = 0
var count = 0
sum = sum + countRecursion([1,2,3, 5, 6, 7], count);
alert(sum);
For recursion: pass data up, return data down.
The original code has a different count variable, being a local variable defined in the function, that is initial set to 0. As such the base case is never reached and the function recurses until the exception is thrown.
In addition to using a variable from an outer scope (or another side-effect) this can also be addressed by by following the recommendation on how to handle recursion, eg.
var countRecursion = function(array, index) {
index = index || 0; // Default to 0 when not specified
if (index >= array.length) {
// Base case
return 0;
}
// Recurrence case - add the result to the sum of the current item.
// The recursive function is supplied the next index so it will eventually terminate.
return array[index] + countRecursion(array, index + 1);
}
I see what you're thinking.
The issue with your code is that everytime you call countRecursion, count goes back to 0 (since it's initialized to 0 within your function body). This is making countRecursion execute infinitely many times, as you're always coming back to count = 0 and checking the first term. You can solve this by either:
Initializing count outside the function body, that way when you do count++, it increases and doesn't get reset to 0.
Passing count along with array as a parameter. That way, the first time you call the function, you say countRecursion(array, 0) to initialize count for you.
Note that you have to do the same for sum, else that will also revert to zero always.
Finally, (and this doesn't have to do with the stack error) you have to actually call return countRecursion(array) to actually move up the stack (at least that's how it is in C++ and what not - pretty sure it applies to javascript too though).
Array sum using recursive method
var countRecursion = function(arr, current_index) {
if(arr.length === current_index) return 0;
current_index = current_index || 0;
return countRecursion(arr, current_index+1) + arr[current_index];
}
document.body.innerHTML = countRecursion([1,2,3,4,5, 6])

Coming Up with a Good Algorithm for a Simple Idea

I need to come up with an algorithm that does the following:
Lets say you have an array of positive numbers (e.g. [1,3,7,0,0,9]) and you know beforehand their sum is 20.
You want to abstract some average amount from each number such that the new sum would be less by 7.
To do so, you must follow these rules:
you can only subtract integers
the resulting array must not have any negative values
you can not make any changes to the indices of the buckets.
The more uniformly the subtraction is distributed over the array the better.
Here is my attempt at an algorithm in JavaScript + underscore (which will probably make it n^2):
function distributeSubtraction(array, goal){
var sum = _.reduce(arr, function(x, y) { return x + y; }, 0);
if(goal < sum){
while(goal < sum && goal > 0){
var less = ~~(goal / _.filter(arr, _.identity).length); //length of array without 0s
arr = _.map(arr, function(val){
if(less > 0){
return (less < val) ? val - less : val; //not ideal, im skipping some!
} else {
if(goal > 0){ //again not ideal. giving preference to start of array
if(val > 0) {
goal--;
return val - 1;
}
} else {
return val;
}
}
});
if(goal > 0){
var newSum = _.reduce(arr, function(x, y) { return x + y; }, 0);
goal -= sum - newSum;
sum = newSum;
} else {
return arr;
}
}
} else if(goal == sum) {
return _.map(arr, function(){ return 0; });
} else {
return arr;
}
}
var goal = 7;
var arr = [1,3,7,0,0,9];
var newArray = distributeSubtraction(arr, goal);
//returned: [0, 1, 5, 0, 0, 7];
Well, that works but there must be a better way! I imagine the run time of this thing will be terrible with bigger arrays and bigger numbers.
edit: I want to clarify that this question is purely academic. Think of it like an interview question where you whiteboard something and the interviewer asks you how your algorithm would behave on a different type of a dataset.
It sounds like you want to subtract a weighted amount from each number. I.E you want to subtract X/sum * amount_to_subtract from each item. You would of course need to round the amount your subtracting. The problem is then making sure that you've subtracted the total correct amount. Also, this depends on your input: are you guaranteeing that that the amount you want to subtract can be subtracted? Here's a rough python implementation, (I think):
def uniform_array_reduction(inp, amount):
total = sum(inp)
if amount > total:
raise RuntimeError('Can\'t remove more than there is')
if amount == total: #special case
return [0] * len(inp)
removed = 0
output = []
for i in inp:
if removed < amount:
to_remove = int(round(float(i)/float(total)*float(amount)))
output.append(i - to_remove)
removed += to_remove
else:
output.append(i)
# if we didn't remove enough, just remove 1 from
# each element until we've hit our mark.
# shouldn't require more than one pass
while removed < amount:
for i in range(len(output)):
if output[i] > 0:
output[i] -= 1
removed += 1
if removed == amount:
break
return output
EDIT: I've fixed a few bugs in the code.
s = Sum(x) - required_sum
do:
a = ceil( s/number_of_non_zeros(x) )
For i=1 to length(x):
v = min(a, x[i], s)
x[i]-=v
s-=v
while s>0
This version needs no sorting.

Categories

Resources