Recursion better understanding - javascript

https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/use-recursion-to-create-a-countdown
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.
// Only change code below this line
function countdown(n){
if (n<1)
return [];
else{
const numbArray = countdown(n-1);
numbArray.push(n)
return numbArray;
}
}
console.log(countdown(5))
// Only change code above this line
comes out like [1 2 3 4 5] instead of [5 4 3 2 1]
I've been breaking my mind forever then I have completed it with the unshift method but felt like it wanted to me use push even though that sends data to the end of the stack

function countdown(max, currentN) {
if (currentN > max)
return [];
else if (currentN <= max) {
const numbArray = countdown(max, currentN + 1);
numbArray.push(currentN)
return numbArray;
}
}
console.log(countdown(5, 1))
// Only change code above this line
basically it just counts up to the end value given at start

else {
const arr = []
arr.push(n)
return arr.concat(countdown(n-1))
}
you can use this code replace, y question reason is y not understand recursion, try to break the point and watch the function execution step by step in the browser or vscode

Related

Javascript recursion related question about push() and unshift() methods working opposite

function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.push(n);
return countArray;
}
}
console.log(countup(5));
After running the above code it returns an array: [1, 2, 3, 4, 5], but push() adds new values at the end of an array so when value of n was 5 it should push 5 to the end of the array and when value of n got 4 it should push 4 at the end of the array like [5,4].
So why not it is returning [5,4,3,2,1] ? It is hard to understand what is happening in this code probably because of this recursion. Isn’t unshift() (which add new values to start of the array) should return [1,2,3,4,5] and push() [5,4,3,2,1] why opposite is happening?
As #Joseph stated in a comment the second to last function call would get pushed to the array first, then it would return that array, where it immediately adds the next number up the call stack.
Here are the steps being taken.
Initial call enters itself recursively n times, where the bottom call returns [] and then [1], [1, 2] ... [1, 2, ..., n] all the way up the call stack where upon the first function call ends and the program does something else.
To get [n, ..., 2, 1] you need to use the Array.prototype.unshift() method, which takes any javascript primitive type, ie String, Number, Boolean, and Symbols, in a comma separated format, like countArray.unshift(4, 5) or countArray.unshift(...anotherArray), and adds them to the beginning of the array.
ie
let someArr = [3, 2, 1];
someArr.unshift(5, 4);
console.log(JSON.stringify(someArr));
// outputs [5, 4, 3, 2, 1]
or
let someArr = [1, 2, 3];
let anotherArr = [5, 4]
someArr.unshift(...anotherArr);
console.log(someArr);
// outputs [5, 4, 1, 2, 3]
Where the output of
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.unshift(n);
return countArray;
}
}
console.log(countup(5));
will be [5, 4, 3, 2, 1] tested with node in Vscode.
One useful way to think about this is to start by imagining you already had a function that does what you want for lower values, and then see how you would write one that works for higher values. That imaginary function should be a black box. All we should know is that it does what we want in the case of lower values. We don't care about its implementation details.
So lets say we had a function imaginaryBlackBox, and we knew that it returned the correct countUp values that we want. So, for instance, we know that imaginaryBlackBox (4) returns [1, 2, 3, 4].
Now, knowing that, how might we write a function that works for an input of 5 as well? How about something like this:
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = imaginaryBlackBox(n - 1);
countArray.push(n);
return countArray;
}
}
Again, we don't know how imaginaryBlackBox works. We just know that it returns the correct result for lower values of n. Our base case remains obvious. For another case, some n greater than 0, we call imaginaryBlackBox(n - 1), and by our basic assumption, we know that will return [1, 2, 3, ..., (n - 1)], which we store in countArray. Then we push n onto that array, to end up with [1, 2, 3, ..., (n - 1), n]. We return that value and we're done.
Now here's the trick. We know an implementation of imaginaryBlackBox -- it's the function we're writing! So we can simply replace it with countUp and know it will work.
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countUp(n - 1);
countArray.push(n);
return countArray;
}
}
This required a few assumptions, and they are important to all recursive functions:
There is at least one base case whose value we can calculate without any recursive call. Here, when n is < 1, we simply return [].
For other cases, we can break down our problem into one or more recursive cases, where the input is in some clear and measurable way closer to a base case, so that subsequent steps will hit a base case in a finite number of calls. Here we reduce n by 1 on every step, so eventually it will be below 1.
Our function is effectively pure: its outputs depend only on its inputs. That means we can't count on changing a global variable or reading from one that might be changed elsewhere. Note that I use the qualifier "effectively" here; it doesn't matter if this function has observable side-effects such as logging to the console, so long as its output is dependent only on its input.
Anytime you have those conditions, you have the makings of a good recursive function.

Spinning the elements of an array clockwise in JS

I am supposed to rotate an array of integers clockwise in JS.
Here is my code for it:
function rotateArray(N, NArray)
{
//write your Logic here:
for(j=0;j<2;j++){
var temp=NArray[N-1];
for(i=0;i<N-1;i++){
NArray[i+1]=NArray[i];
}
NArray[0]=temp;
}
return NArray;
}
// INPUT [uncomment & modify if required]
var N = gets();
var NArray = new Array(N);
var temp = gets();
NArray = temp.split(' ').map(function(item) { return parseInt(item, 10);});
// OUTPUT [uncomment & modify if required]
console.log(rotateArray(N, NArray));
The code accepts an integer N which is the length of the array. The input is as follows:
4
1 2 3 4
The correct answer for this case is supposed to be
4 1 2 3
But my code returns
4 1 1 1
I cannot find where my code is going wrong. Please help me out.
All you need to do is move one item from the end of the array to the beginning. This is very simple to accomplish with .pop() (removes an item from the end of an array), then declare a new array with that element as the first:
function rotateArray(N, NArray) {
const lastItem = NArray.pop();
return [lastItem, ...NArray];
}
console.log(rotateArray(1, [1, 2, 3, 4]));
Doing anything else, like using nested loops, will make things more unnecessarily complicated (and buggy) than they need to be.
If you don't want to use spread syntax, you can use concat instead, to join the lastItem with the NArray:
function rotateArray(N, NArray) {
const lastItem = NArray.pop();
return [lastItem].concat(NArray);
}
console.log(rotateArray(1, [1, 2, 3, 4]));
If you aren't allowed to use .pop, then look up the last element of the array by accessing the array's [length - 1] property, and take all elements before the last element with .slice (which creates a sub portion of the array from two indicies - here, from indicies 0 to the next-to-last element):
function rotateArray(N, NArray) {
const lastItem = NArray[NArray.length - 1];
const firstItems = NArray.slice(0, NArray.length - 1);
return [lastItem].concat(firstItems);
}
console.log(rotateArray(1, [1, 2, 3, 4]));
function rotate(array,n){
Math.abs(n)>array.length?n=n%array.length:n;
if(n<0){
n=Math.abs(n)
return array.slice(n,array.length).concat(array.slice(0,n));
}else{
return array.slice(n-1,array.length).concat(array.slice(0,n-1));
}
}
console.log(rotate([1, 2, 3, 4, 5],-3));
The answer by #CertainPerformance is great but there's a simpler way to achieve this. Just combine pop with unshift.
let a = [1,2,3,4];
a?.length && a.unshift(a.pop());
console.log(a);
You need to check the length first so you don't end up with [undefined] if you start with an empty array.

Recursive function that creates an array from 0 to n (JavaScript)

I've been reading a lot about recursive functions recently though I wasn't able to figure this one out until today. I think I now understand recursion better. Hopefully I can help someone else who is still struggeling with it:
function count(n) {
if (n === 1) {
return [1];
} else {
var numbers = count(n - 1);
numbers.push(n);
return numbers;
}
}
console.log(count(3));
The result of count(3) will be: [1, 2, 3]
We pass in 3 into count(n). Since n is not equal to 1 we go straight to the else statement. numbers = count(3 - n) or numbers = count(2) if we pass in n. What happens next is recursion:
Since we don't know what exactly count(2) is we have to run it to figure out. So we run count(2). n is not equal to 1 so we go to the else statement again. numbers = count(1). Recursion again. We put in 1 for n and this time the function returns [1].
Now since we know that count(1) = [1] we are able to solve count(2). count(2) is numbers = count(1) or numbers = [1]. This time we go ahead in our code and push in n numbers.push(n) which is 2. So count(2) returns [1, 2]. Now since we know the result for count(2) let's solve count(3). count(3) is numbers = count(2) or numbers = [1, 2] putting in our result. Now push gets activated and voila, our result for count(3) is [1, 2, 3].

How to understand this recursion

Hello all I am trying to understand this solution to combination sum.
function combinationSum(candidates, target) {
var result = [];
if ((candidates == null) || (candidates.length == 0)) {
return result;
}
var cur = [];
candidates = candidates.sort((a, b) => a - b)
csh(candidates, target, cur, result, 0);
return result;
};
function csh(cand, target, cur, result, j) {
//console.log(cur);
if (target == 0) {
var temp = cur.slice();
result.push(temp);
return;
}
for (var i = j; i < cand.length; i++) {
if (target < cand[i]) {
return;
}
//console.log(cur);
cur.push(cand[i]);
console.log(cur);
csh(cand, target - cand[i], cur, result, i);
cur.pop();
}
}
https://leetcode.com/problems/combination-sum/description/
While I understand the basic principles of recursion this problem is a little bit lost on me. So for example for the input:
candidates = [2,3,6,7]
target = 7
When you first enter the function cur is empty so our first iteration is:
[],
[2],
[2,2]
And then we keep adding cand[i] which is currently 2
[2,2,2]
However at this point, target = 1 which is less than cand[i] which is 2 so we return. And since we're returning we pop off the stack which pops the last 2 off the stack. Since we've returned we increment i and then we add 3 to cur
[2,2,3]
Since our target array is equal to 0 we now return again and my question is, at this point do we keep returning until cur is empty and continue the function like the following?
[2,2]
[2]
[]
[6]
[]
[7]
I'm just trying to understand what is being done in this function.
target is local to each invocation of the function. target is 0 only for some invocations of the function. Notice that the recursive invocation is:
csh(cand, target - cand[i], cur, result, i);
The target in that scope has not change, but the invocation of csh currently being entered will have a lower value for its target. When that function returns and the program flow reenters that other level, we resume using the higher value of target, insted of the reduce value target - cand[i] that was supplied to the subcall.
The algorithm will try all other possibilities on the [2,2,...] path as well, before changing the second element to the next alternative. Then it will explore the [2,3,...] space, and the [2,6,...] space, and ultimately all the [3,...], [6,...] and [7,...] possibilities as well.
The algorithm always goes as deep as a possible (i.e., as long of an array as possible) when it can do so without going over the original limit.
Note that it does not produce [2,3,2], because an earlier candidate cannot come after a later one (so a 2 can never be subsequent to a 3 in a result). It enforces this by making the for look start at i = j, where j is the array-depth of the last candidate used, so when the result-in-progress ends with the nth candidate, it only considers nth and higher candidates. this is of practical value because the algorithm only returns one permutation of each value result set: [2,2,3] and [2,3,2] contain the same set of values.
I completely understand that recursion can be very difficult to understand and to explain as well, but here is my take on it.
When csh is called for the 1st time, this is what is being passed
csh(cand, 7, [], [], 0)
Now from the for loop, i = 0, function called is
csh(cand, 5, [2], [], 0)
from the loop, i = 0, function called is
csh(cand, 3, [2,2], [], 0)
from the loop, i = 0, function called is
csh(cand, 1, [2,2,2],[],0)
from the for loop, target(1) < cand[0](2), so return to step Step 4 and pop the last 2 from [2,2,2] resulting in [2,2]
from the loop i = 1, function called is
csh(cand, 0, [2,2,3], [], 1)
here, target == 0 condition is met. so, [2,2,3] is pushed in the result. and then return to step 4. again, 3 is popped from [2,2,3].
from the loop i = 2, target(3) < cand[2](6), so return to step 3. and pop 2 from [2,2] resulting in [2].
from the loop i = 1, function called is
csh(cand, 2, [2,3], [[2,2,3]], 1)
from the loop i = 1, target(2) < cand[1](1) so return to step 9.
and so no...
Basically, each and every combination will be checked.
[2,2,2]
[2,2,3] --> added to result
[2,3,3]
[2,6]
[2,7]
[3,3,3]
[3,6]
[3,7]
[6,6]
[6,7]
[7] --> added to res

Re-usable while loop function isn't looping

Still a little new to javascript so this might be an easy fix but could anyone tell me why the following code does not work?
I am trying to create a reusable function that will increment from count to countTo in increments of countBy. I would like to vary those increments (either all evens, all odds, only numbers divisible by 5, etc). Right now it is just printing out -10 and not looping. Also it doesn't know count exists unless i make it global and I'm not sure why.
Thanks in advance!
EDIT: initialized count with count = 0, it works now. I'm still not sure why it doesn't just recognize the value of count when i pass it in as an argument though. Are they not the same "count"?
//count = incrementing variable
//countTo = final result
//countBy = how we should increment count
var count;
function looping(count, countTo, countBy) {
while(count <= countTo) {
console.log(count);
count = countBy(count);
}
}
console.log("-10 to 19");
var counting1 = looping(-10, 19, function () {
return count++;
});
Since this question is tagged with functional-programming I'll answer it using functional techniques.
Where you went wrong
var count;
function looping(count, countTo, countBy) {
// because you named a parameter `count`, you shadowed the external `count` variable
while(count <= countTo) {
console.log(count);
// this doesn't reassign outer count
// instead it reassigns local count and is discarded after function exits
count = countBy(count);
}
}
Functional programming advises against things like this tho anyway – and in some languages, it's outright impossible to do. External state is discouraged and variable reassignment is usually an indicator for problems. Let's start by adjusting how the code should work
var count; // no need for external state
var counting1 = looping(-10, 19, function (count) { // use local parameter
return count++; // ++ is a mutating function
return count + 1
});
Instead of relying upon external state, count, we will pass count into the function each loop. And rather than using count++, although it would work in JavaScript since numbers are already immutable, it's better to get in the habit of using non-mutating functions. Also count + 1 makes it clear that a mutation is not necessary here and things like count + 2 would work if we wanted to count by twos – or count * 2 if we wanted to double the counter each time, etc.
To make this work, it's actually quite easy. Below is a recursive function which continues looping until from is greater than to. Each loop will send the current counter value into the callback, f, which is expected to return the next value of the counter.
function looping (from, to, f) {
if (from > to)
return from
else
return looping (f (from), to, f)
}
looping (-3, 3, function (count) {
console.log (count)
return count + 1 // count by 1
})
// -3, -2, -1, 0, 1, 2, 3
// => 3
looping (-3, 3, function (count) {
console.log (count)
return count + 2 // count by 2
})
// -3, -1, 1, 3
// => 3
There's nothing wrong with using a while-loop, but it's important to keep any mutable state localized to the looping function. The important lesson here is that the usage of our function looks exactly the same and even tho the implementation changed, there are still no side effects.
function looping (from, to, f) {
while (from < to) from = f (from)
return from
}
looping (-3, 3, function (count) {
console.log (count)
return count + 1 // count by 1
})
// -3, -2, -1, 0, 1, 2, 3
// => 3
looping (-3, 3, function (count) {
console.log (count)
return count + 2 // count by 2
})
// -3, -1, 1, 3
// => 3
count doesn't have a value by the time you increment it, hence it becomes NaN.
You are making a simple function complex by using inline function call which is not correct. If question is about how to get this functionality, here is simple solution.
function looping(count, countTo, countBy) {
while(count <= countTo) {
console.log(count);
count += countBy;
}
}
console.log("-10 to 19");
var step = 2;
var counting1 = looping(-10, 19, step);

Categories

Resources