Use Recursion to Create a CountdownPassed (JS Algorithm) - javascript

Question
We have defined a function called countdown with one parameter (n). The function should use recursion to return an array containing the integers n through 1 based on the n parameter. If the function is called with a number less than 1, the function should return an empty array. For example, calling this function with n = 5 should return the array [5, 4, 3, 2, 1]. Your function must use recursion by calling itself and must not use loops of any kind.
function countdown(n, newArr = []){
if(n == 1){
return newArr;
}
newArr.push(n);
return countdown(n - 1)
}
console.log(countdown(5));
My Question
Is there a way to fix this code so that it works?
I can provide an alternative solution, but I do not understand it:
function countdown(n) {
if (n < 1) {
return [];
} else {
const arr = countdown(n - 1);
arr.unshift(n);
return arr;
}
}

The problem is that you do not pass on the array to the recursive call, so each recursive execution creates a new, empty array. As a consequence, it does not return the array that had a value pushed to it, but the new, empty one that is coming back from the recursive calls.
Secondly, you never push value 1 to the array. So it would be better to stop the recursion at 0 instead of 1.
So taking those two fixes, you get this:
function countdown(n, newArr=[]) {
if (n <= 0) {
return newArr;
}
newArr.push(n);
return countdown(n - 1, newArr)
}
console.log(countdown(5));
Your alternative solution is clean, because it does not need to pass an array as argument. It uses the returned array to add the next value to it (in front of it). It would have my preference.
To understand how it works, print out the intermediate values:
function countdown(n) {
if (n < 1) {
console.log("At the end of recursion. Creating and returning an empty array.");
return [];
} else {
const arr = countdown(n - 1);
console.log("Got the following array back from the recursive call:");
console.log(JSON.stringify(arr));
arr.unshift(n);
console.log("Prefixing it with " + n + " and returning the result:");
console.log(JSON.stringify(arr));
return arr;
}
}
var result = countdown(5);

yes, you can modify your solution like that
function countdown(n){
if(n == 0){
// stop the function at 0 so it will not be included in the array
return [];
}
// concat the value of n as an array with the value less than it
return [n].concat(countdown(n - 1))
}
console.log(countdown(5));
the problem in your solution is that your array initialized as an empty array every time so the final answer will be an empty array

You need to hand over the result array for the recursive call. And you need to check if no value is left, ten return the result array.
function countdown(n, result = []) {
if (n < 1) return result;
result.push(n);
return countdown(n - 1, result);
}
console.log(countdown(5));
As another approach, you could return an array and for the exit condition take the final value, otherwise take n and the spreaded result of the recursive call.
function countdown(n) {
if (n < 1) return [];
return [n, ...countdown(n - 1)];
}
console.log(countdown(5));

At this point we will create the countdown function which call itself and called recursion.
function countdown(n) {
if (n < 1) {
return [];
} else {
console.log(n, "before calling");
const arr = countdown(n - 1);
console.log(n, "after calling");
return arr;
}
}
console.log(countdown(5));
And now when we know that the "before calling" is place where n is decrease and the "after calling" is place where n is increase, based on that we can do this.
const arr = [];
function countdown(n) {
if (n < 1) {
return arr;
} else {
arr.push(n);
return countdown(n - 1);;
}
}
console.log(countdown(5));

Related

A range of numbers in js

So I wanted to make a recursive function that pushes a range of numbers inside of an array.
So I did the following:
function rangeOfNumbers(startNum, endNum) {
let arr = [];
if (startNum != endNum) {
rangeOfNumbers(startNum++, endNum);
arr.push(startNum);
} else {
arr.push(endNum);
}
return arr;
};
console.log(rangeOfNumbers(1, 5));
so the way I think that should work is that in each iteration startNum should be +1 and should be pushed inside of the array and when startNum gets to endNum's value in this case 5 we should push endNum and end the recursion, why is my logic faulty, cuz what happens now is that my function exceeds the maximum call stack.
Another thing I tried was:
function rangeOfNumbers(startNum, endNum) {
let arr = [];
if (startNum == endNum) {
return arr.push(endNum);
} else {
rangeOfNumbers(startNum++, endNum);
arr.push(startNum);
}
return arr;
};
still exceeds the callstack, why does that happen? :(
You are redefining your arr variable on every call, and never using the arrays returned from deeper calls. You can either pass a single array reference as Basto does in their answer, or you can run through the recursion and only define the array on the terminal call and then unshift() each startNum into the returned array.
function rangeOfNumbers(startNum, endNum) {
const arr = startNum < endNum ? rangeOfNumbers(startNum + 1, endNum) : [];
arr.unshift(startNum);
return arr
};
console.log(rangeOfNumbers(1, 5));
unshift() is quite slow though. You can alter the logic to use push() by decrementing 'endNum' instead of incrementing 'startNum', and pushing 'endNum' on each call.
function rangeOfNumbers(startNum, endNum) {
const arr = startNum < endNum ? rangeOfNumbers(startNum, endNum - 1) : [];
arr.push(endNum);
return arr
}
console.log(rangeOfNumbers(1, 5))
Or using spread syntax (...)
function rangeOfNumbers(startNum, endNum) {
return startNum <= endNum
? [startNum, ...rangeOfNumbers(startNum + 1, endNum)]
: [];
}
console.log(rangeOfNumbers(1, 5));
You are only returning the array from the first iteration.
You need to make the array one of your arguments on your recursive function so all the pushes are into the same array
function rangeOfNumbers(startNum, endNum, arr =[]) {
if(startNum < endNum) {
arr.push(startNum);
rangeOfNumbers(startNum + 1, endNum, arr);
}else{
arr.push(endNum);
}
return arr;
};
Edit:
You probably also want to call the recursion after the push so they are all in order.
And I also changed the comparison operator to a < to prevent stack overload if the function is used wrong.
You have to put the array in parameters :
let arr = [];
function rangeOfNumbers(startNum, endNum, arr) {
if (startNum !== endNum) {
arr.push(startNum);
rangeOfNumbers(startNum + 1, endNum, arr);
} else {
arr.push(endNum);
}
return arr;
}
console.log(rangeOfNumbers(1, 5, arr));

returning an array using recursion

I'm pretty new to recursion and Im having trouble returning the value I want into an array. I have a simple function called countDown which needs to take in an argument of type integer in this case the parameter/argument is the letter (n). and I want to count backwards starting from the number (n) all the way to 1. so for example if I pass in the number 4 I would like to return [4, 3, 2, 1] and I need to do this recursively. I believe I have gotten close because in my code I simply put a console.log(n) and I can see now the numbers are printing out 4, 3, 2, 1 however I need to return these numbers in an array and I am pretty lost. I'm familiar with .push() but that doesn't seem to work and I have tried .concat() but I'm not able to get it to work either. Any help is much appreciated!
function countDown(n) {
if (n < 1) {
return [];
} else {
console.log(n);
let j = countDown(n - 1);
}
}
countDown(4);
You are indeed pretty close. There are going 2 things wrong in your snippet.
You do not return a value if n is not smaller than 1 (the else scenario).
You do log n, but don't add it to the result.
Without changing a lot, a solution might look like this:
function countDown(n) {
if (n < 1) {
return [];
} else {
// get the countdown of n - 1
const ns = countDown(n - 1);
// add the current n in front
ns.unshift(n);
// return the list
return ns;
}
}
console.log(countDown(4));
Make sure you return something in every case!
You're doing it for the base case (return []), but you need to return something that includes the recursive call in other cases (return // something that uses countDown(n-1)).
function countDown(n) {
if (n < 1) return [];
return [n, ...countDown(n-1)];
}
console.log(countDown(4));
You appear to be nearly there, but when using recursion state will need to be passed to the next iteration.
So below is an example where the arr parameter if left blank will create the initial array, and then the recursive part can just keep passing this down.
function countDown(n, arr) {
if (!arr) arr = [];
if (n < 1) {
return arr;
} else {
arr.push(n);
return countDown(n -1, arr);
}
}
console.log( countDown(4) );
Is this does what you want?
let arr = [];
function countDown(n) {
if (n < 1) {
return [];
} else {
arr.push(n);
countDown(n - 1);
}
}
countDown(4);
console.log(arr);
Try something like this
function countDown(n, a = []) {
if (n < 1) {
console.log(a);
return a;
} else {
a.push(n);
let j = countDown(n - 1,a);
}
}
countDown(4);

javascript function to find the second largest element in an array

I am completing the hackerrank's 10 days of javascript challenge. The question:
write a function to take an array as an argument and then return the second largest element in the array.
I have written the code but my code is returning the largest element and not the second largest as asked.
function getSecondLargest(nums) {
// Complete the function
var largest=nums[0];
for(let i=1;i<nums.length;++i)
{
if(nums[i]>largest)
largest=nums[i];
}
var large=nums[0];
for(let j=1;j<nums.length;++j)
{
if(large<nums[j]&&large<largest)
large=nums[j];
}
return large;
}
When input array nums={2,3,6,6,5} the result is coming 6 while expected output is 5. Please help and point out the errors in the function code below.
should not initialize large with first value var large=nums[0]; because it may appear the biggest value and won't work
should use nums[j]<largest instead of large<largest as mentioned above
I think don't need second loop as all checks can be done in first loop, and you can assign prev largest to large whenever you change it:
function getSecondLargest(nums) {
var largest = nums[0];
var large;
for (let i = 1; i < nums.length; ++i) {
if (nums[i] > largest) {
large = largest;
largest = nums[i];
} else if (nums[i] > large || typeof large === 'undefined') {
large = nums[i]
}
}
return large;
}
console.log(getSecondLargest([5,1-2,3]))
console.log(getSecondLargest([-5,1,-2,3]))
GET SECOND LARGEST
first, I create new array with unique values.
let arr = [...new Set(nums)];
second, sort value using built-in function .sort().
note : by default .sort() always sorts asciibetically, but for some testcase, it doesn't work. So, I put (a, b) => { return a - b } to make sure it will work properly.
arr = arr.sort((a, b) => { return a -b });
third, get the value from arr
let result = arr[arr.length - 2] || arr[0];
finally, return the result
return result
function getSecondLargest(nums) {
let arr = [...new Set(nums)];
//Javascript's array member method .sort( always sorts asciibetically.
arr = arr.sort((a, b) => { return a - b });
let result = arr[arr.length - 2] || arr[0];
return result
}
Just one minor change:
Use nums[j]<largest instead of large<largest in the second for loop
function getSecondLargest(nums) {
// Complete the function
var largest=nums[0];
for(let i=1;i<nums.length;++i)
{
if(nums[i]>largest)
largest=nums[i];
}
var large;
//To ensure that the selected number is not the largest
for(let j=0;j<nums.length;++j)
{
if (nums[j] !== largest){
large = nums[j];
break;
}
}
for(let j=1;j<nums.length;++j)
{
if(large<nums[j]&&nums[j]!=largest)
large=nums[j];
else
console.log(large)
}
return large;
}
var secondLargest = getSecondLargest([6,3,6,6,5]);
console.log("Second largest number", secondLargest);
If you want to avoid using library functions like #ifaruki suggests, this line
if(large<nums[j]&&large<largest)
should read
if (large<nums[j] && nums[j] < largest)
Sorting and picking the second or second-to-last value fails when there are duplicates of the highest value in the input array.
Another easiest logic is to remove duplicates from the array and sort.
let givenArray = [2, 3, 6, 6, 5];
let uniqueArray = [...new Set(givenArray)];
console.log("The second largets element is", uniqueArray.sort()[uniqueArray.length - 2]);
I know you had your question answered, just thought I would provide my solution for any future users looking into this.
You can use reduce to go through the array while remembering the two largest numbers so far.
You just make a simple reduction function:
function twoMax(two_max, candidate)
{
if (candidate > two_max[0]) return [candidate,two_max[0]];
else if (candidate > two_max[1]) return [two_max[0],candidate];
else return two_max;
}
And then you use it for example like this:
let my_array = [0,1,5,7,0,8,12];
let two_largest = my_array.reduce(twoMax,[-Infinity,-Infinity]);
let second_largest = two_largest[1];
This solution doesn't require sorting and goes through the array only once.
If you want to avoid using **sort method. I think here's the easiest logic to do that, which will also work in arrays where there's duplicates of largest integer exists.
function getSecondLargest(arr) {
const largest = Math.max.apply(null, arr);
for (let i = 0; i < arr.length; i++) {
if (largest === arr[i]) {
arr[i] = -Infinity;
}
}
return Math.max.apply(null, arr);
}
console.log(getSecondLargest([5, 7, 11, 11, 11])); //7

function is not returning any value

I need to write a recursive function that should return the largest number in a given array,
I'm using the method .splice() to remove the smaller numbers. When I have just one element in my array I will return that element witch would be the biggest number in the array
the logic seems working but is not returning anything, any ideas?
function findMax(arr){
// This function returns the largest number in a given array
if (arr.length === 1){
const bigNum = arr.pop();
return bigNum
}
else if (arr[0] > arr[1]){
arr.splice(1,1)
findMax(arr)
}
else{
arr.splice(0,1)
findMax(arr)
}
}
y = findMax([1,6,8,2,10,5]);
y
undefined
You need to return the results of the recursion:
function findMax(arr){
// This function returns the largest number in a given array
if (arr.length === 1){
const bigNum = arr.pop();
return bigNum
}
else if (arr[0] > arr[1]){
arr.splice(1,1)
return findMax(arr)
}
else{
arr.splice(0,1)
return findMax(arr)
}
}
y = findMax([1,6,8,2,10,5]);
console.log(y)
Another option if you're looking for something a little simpler is to compare with the result of the recursion directly and return the largest:
function findMax(arr){
// This function returns the largest number in a given array
if (arr.length <=1) return arr[0]
let [head, ...rest] = arr
let rec = findMax(rest)
return head > rec ? head : rec
// or just:
// return Math.max(head, findMax(rest))
}
y = findMax([10, 9, 14, 3, 1, -2]);
console.log(y)

Javascript unlimited nested array handling

I am trying to have fun with my buddy who solved the problem mentioned in 8m 7s, and for me it is already 20m gone. I can't figure out how to handle unlimited nested array in javascript.
The problem is this:
// i will be an array, containing integers, strings and/or arrays like itself.
// Sum all the integers you find, anywhere in the nest of arrays.
So
arraySum([[1,2,false],'4','5']) will return 3 (passed)
arraySum([[1,2,3],4,5]) will return 15 (passed)
arraySum([[[[[[[[[1]]]]]]]], 1]) will return 2 (failed)
The code I wrote is:
function arraySum(i) {
sum = 0;
tmp =0;
for (var a=0; a<i.length; a++){
if (i[a] instanceof Array) {
ar = i[a];
for (var j=0; j<ar.length; j++){
tmp +=ar[j];
}
}
if (typeof i[a] == "number")
sum += i[a];
console.log(sum);
}
return sum + tmp;
}
As you can see it does not handle the last situation that I failed as I can't figure out how to handle unlimited nest in JS.
Any idea will be much appreciated.
Also try to finish it before 8m 7s, which my buddy finished in.
Inside of the if (i[a] instanceof Array) { part, you'll have to use recursion to operate on nested arrays with the same arraySum function, not just use another loop. Try this:
var arraySum = (function () {
"use strict";
var sumFunc, isArray;
sumFunc = function (arr) {
var sum, i, j, cur, toAdd;
sum = 0;
for (i = 0, j = arr.length; i < j; i++) {
cur = arr[i];
toAdd = 0;
if (isArray(cur)) {
toAdd = sumFunc(cur);
} else if (typeof cur === "number") {
toAdd = cur;
}
sum += toAdd;
}
return sum;
};
isArray = Array.isArray || function (obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
return sumFunc;
}());
DEMO: http://jsfiddle.net/Q7JPM/1
The function just loops through all items in an array, and returns the sum of any numbers found inside. If the item is an array itself, it calls arraySum and passes that array...adding the result to the sum. If it's a number, it simply adds that to the sum.
You have to use recursion:
http://jsfiddle.net/HMnat/2
function arraySumRec(theArray)
{
var sum=0;
for (var i=0;i<theArray.length;i++)
{
if (theArray[i] instanceof Array)
{
sum=sum+arraySumRec(theArray[i]);
}
else
{
if (typeof(theArray[i])=="number")
{
sum=sum+theArray[i];
}
}
}
return sum;
}
Took me 3 minutes 47 seconds (due to a typo, ha ha).
The Javascript Array reduce method is perfect for solving this kind of problem. The reduce method takes a function with at least two arguments: the accumulator and the current element of the array. In the body of the function, you specify how each element should affect the accumulator. The second argument to the function is the starting value of the accumulator.
function sum(x) {
return x.reduce(function(accumulator, currentValue) {
if (typeof currentValue === "number") {
return accumulator + currentValue;
} else if (currentValue instanceof Array) {
return accumulator + sum(currentValue);
} else {
return accumulator;
}
}, 0);
}
JSFIDDLE
The function sum takes an array, and the reduce method reduces it to a single value. In the "else if" branch, where we find a nested array, we can simply call sum on it, get back a single value, and add that to our accumulator. In the "else" branch, we haven't found the kinds of values we're interested in so we leave the accumulator unchanged.
The documentation at MDN provides a good explanation of Array reduce with examples.
function arraySum(i) {
var l = i.length, sum = 0;
while (l--) {
if (typeof i[l] !== 'number' && !(i[l] instanceof Array)) continue;
if (i[l] instanceof Array) { sum += arraySum(i[l]); continue; }
sum += i[l];
}
return sum;
}
Non-Recursive using a stack.
function arraySum(arr)
{
var sum = 0;
while(arr.length != 0)
{
var value = arr.pop();
if(value instanceof Array)
{
for (i= 0; i< value.length; ++i)
arr.push(value[i]);
}
else if(typeof value === "number")
sum += value;
}
return sum;
}
var arr = [1, 2, [3, 4, [[[5]]]]];
console.log(arraySum(arr));
If we focus on the right parts, we can save ourselves the tedium from focusing on the wrong parts -
function arraySum (t)
{ switch (t?.constructor)
{ case Array:
return t.reduce((r, v) => r + arraySum(v), 0)
case Number:
return t
default:
return 0
}
}
console.log(arraySum([[1,2,false],'4','5']))
console.log(arraySum([[1,2,3],4,5]))
console.log(arraySum([[[[[[[[[1]]]]]]]], 1]))
3
15
2
If ?. is not yet supported in your environment, you can swap it out -
switch (t?.constructor)
switch (t && t.constructor) // <- where ?. is unsupported
Edit: it took me 2,769 days to answer the question but only a few minutes to write it :D

Categories