I was doing a coding algorithm to find the nth number which is the sum of the (n-1)th and (n-2)th numbers.
Here was the solution
function getNthFib(n, hashTable = {1: 0, 2: 1}) {
if (n in hashTable) {
return hashTable[n]
} else {
hashTable[n] = getNthFib(n - 1, hashTable) + getNthFib(n - 2, hashTable)
return hashTable[n]
}
}
can anyone explain to me in the else block of what is actually happening? i am confused with this recursive concept
Recursive Fibonacci works beacse the next number is the last two numbers combined. Eg 3 + 5 = 8 and then 5 + 8 = 13. The recursive solution finds the value of the 2 numbers to add to the next, and then finds the numbers before, etc. The hashtable, which is a plain object, maps precomputed values so it does not have to compute them again, as recursive Fibonacci has a O(n!) time complexity without a table or cache.
Related
While solving online code exercises, I came across this one:
Given a 1-dimensional array of numbers and the number of queries, where each query has start index a, end index b and a number c, find the sum of numbers between indexes a and b (inclusive). For each occurrence of zero within the range [a,b], add the value of c to the sum. For example, numbers = [4,6,0,10], queries = [1,3,20] => for this example we need to get the sum of [4,6,0] (indexes 1-3), and because [4,6,0] has 0, we also need to add 20.
This is my code so far:
function findSum(numbers, queries) {
//declare empty array that will store the numbers
let arr = []
// declare initial sum
let sum = 0;
// get the last element of queries (c)
let lastElement = queries[0].pop()
// loop through queries and push numbers to arr, to sum them in the end
queries[0].slice(0, 2).forEach(x => {
arr.push(numbers[x - 1])
})
// check if arr has 0
let zero = arr.filter(el => el === 0)
// if arr has 0, according to the instructions we need to add the c of the q
if (zero.length != 0) {
sum = arr.reduce((a, b) => a + b, 0) + lastElement
}
else {
sum = arr.reduce((a, b) => a + b, 0)
}
return sum
}
My code works if queries is an array, but in some test cases queries may be array of arrays like [ [ 2, 2, 20 ], [ 1, 2, 10 ] ]. I don't know know how to check the numbers in case if queries is array of arrays. Any suggestions are greatly appreciated.
in some test cases queries may be array of arrays
I would expect that this would always be the case, not just in some cases. This is also clear from your code:
queries[0].pop()
This assumes a 2-dimensional array! The problem is not that you sometimes get a 1-dimensional array and other times a 2-dimensional array. The problem is that although you always get a 2-dimensional array, your code is only looking at the first query -- the one that sits at queries[0].
Instead, you should loop over all queries.
I also assume that the return value of your function must be an array, having an answer for each of the queries. This means that you probably want to have code like this:
function findSum(numbers, queries) {
return queries.map(query => {
// solve the single query
return sum;
});
}
Note that your code is not making the sum correctly, as your arr will have a length of 2 (arr.push(numbers[x - 1]) is executed exactly twice), yet the query could indicate a range with 100 values and you should derive the sum of those 100 values, not just of two.
But even if you fix all that, you'll end up with an inefficient solution that will have to iterate over many values in the input array multiple times. This needs a smarter approach.
Try to think of a way to analyse the input before processing any queries yet. Would there be something useful you could build that would help to quickly get a sum of a subarray without having to iterate that subsection again?
Here are some hints:
Hint #1
Use the following truth:
sum(numbers.slice(start, end)) == sum(numbers.slice(0, end)) - sum(numbers.slice(0, start - 1))
Hint #2
What if you would know the sum from the start of the array to any given index? Like a running sum... So for numbers=[4, 8, 0, 3] you would know [4, 12, 12, 15]. Would that help in calculating a sum for a certain range of [start, end]?
Hint #3
How could you apply the same principle for the special treatment of zeroes?
I need to write a function to calculate minimal sum of the local maximum of the subarrays of an array where every item is a positive integer with possible duplicates.
For example, we have an array [2, 3, 1, 4, 5, 6] and the number of sub arrays is 3. We want to get the min sum of the local max of the sub arrays. What that means is that, for example, one possible way to divide the current array into 3 sub arrays is [[2,3], [1], [4,5,6]] and the local maxs for each subarray is 3, 1, 6 respectively. And the sum of the local maxs is 3 + 1 + 6 = 10. For this particular array, [2, 3, 1, 4, 5, 6], this is the minimal sum of all its possible sub-array variations.
My approach is to first get all the possible sub-array variations for a given array. and get the min sum of them.
function getSubarrays(array, numOfSubarray) {
const results = []
const recurse = (index, subArrays) => {
if (index === array.length && subArrays.length === numOfSubarray) {
results.push([...subArrays])
return
}
if (index === array.length) return
// 1. push current item to the current subarray
// when the remaining items are more than the remaining sub arrays needed
if (array.length - index - 1 >= numOfSubarray - subArrays.length) {
recurse(
index + 1,
subArrays.slice(0, -1).concat([subArrays.at(-1).concat(array[index])])
)
}
// 2. start a new subarray when the current subarray is not empty
if (subArrays.at(-1).length !== 0)
recurse(index + 1, subArrays.concat([[array[index]]]))
}
recurse(0, [[]], 0)
return results
}
function getMinSum(arrays) {
return arrays.reduce(
(minSum, array) =>
Math.min(
minSum,
array.reduce((sum, subarray) => sum + Math.max(...subarray), 0)
),
Infinity
)
}
getMinSum(getSubarrays([[2,3], [1], [4,5,6]], 3)) // 10
However, I think the time complexity for my solution is really high. My guess is that it is on the order of 2^n (feel free to correct me if I am wrong). I wonder if there is a more efficient way to calculate this.
The first thing that comes to mind is dynamic programming.
Let dp[i][j] be the minimal sum of local maximums of array[0..i] (left border included, right border excluded) divided into j subarrays. dp[0][0] = 0 (this is an initial value for empty array[0..0]), and for simplicity initialise all other dp[i][j] with some large enough number to denote meaningless of not calculated values (larger than sum of elements in array in this case is enough).
Your answer obviously is the value of dp[array.length][numOfSubarray].
How do you calculate values of the dp? Actually pretty easy. dp[i][j] is the minimum among dp[k][j - 1] + max(array[k..i]) (where k < i). Let's analyse this formula:
dp[k][j - 1] + max(array[k..i])
# ^ ^
# This term is the minimal sum of local maximums
# of array[0..k] divided into j-1 subarrays.
# |
# This term is maximum of your new j-th subarray.
Also make sure that all the dp[k][j - 1] were calculated beforehand (for example by calculating dp[i][1] at first, then dp[i][2], then dp[i][3] and so on).
Now let's write it altogether (naive approach just for now).
dp[0][0] = 0
for newSubarrayNumber in range(1, numOfSubarray + 1):
for previousEnd in range(0, array.length):
for newEnd in range(previousEnd + 1, array.length + 1):
# Formula from above.
dp[newEnd][newSubarrayNumber] =
min(dp[newEnd][newSubarrayNumber],
dp[previousEnd][newSubarrayNumber - 1] + max(array[previousEnd..newEnd]))
# Your answer.
print(dp[array.length][numOfSubarray])
As you can see we've got polynomial complexity, now it's O(numOfSubarray * array.length^3) (two array.length for two nested loops and one more because of max(array[previousEnd..newEnd])).
Also we can optimise our algorithm. It makes no sense to always calculate min(array[previousEnd..newEnd]), because previously we did that for newEnd - 1 and we can reuse that value. That brings us to the following algorithm:
for newSubarrayNumber in range(1, numOfSubarray + 1):
for previousEnd in range(0, array.length):
maxElement = 0
for newEnd in range(previousEnd + 1, array.length + 1):
# maxElement replaces max(array[previousEnd..newEnd]).
maxElement = max(array[newEnd - 1], maxElement)
dp[newEnd][newSubarrayNumber] =
min(dp[newEnd][newSubarrayNumber],
dp[previousEnd][newSubarrayNumber - 1] + maxElement)
That's O(numOfSubarray * array.length^2) (just because of loops, no extra complexity multiplier).
I believe one can optimise it even more (maybe using some advanced data structures), feel free to comment. Also even better approach for this particular problem could be some sort of greedy algorithm (like having small subarrays closer to border of an array and one big chunk in the center but that needs to be proven).
We can have O(n^2) by using a dynamic program where the state is (1) the index of the rightmost element considered so far, and (2) the length of the subarray ending at (1).
The information we need to store about those two things is deterministic -- we need the maximum value in subarray (2) and the best solution overall ending at (1).
Then, to consider the next element, we have two choices for each length in (2): either add the element to the subarray, or start a new subarray.
For each element, we would examine O(n) lengths for a total of O(n^2).
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].
I'd like to check if n arrays all contain the same integers in JavaScript? What is the most efficient way?
if you have only numbers in the arrays - use some variation of the basic CRC algorithm - the complexity is O(n) per array so it would be the fastest possible https://en.wikipedia.org/wiki/Cyclic_redundancy_check
Similar idea, calculate sum(array) and product(array), you can calculate both values with O(n). For example:
1, 5, 6, 7 ,8 sum=27, prod=1680
7, 8, 1, 5, 6 sum=27, prod=1680
but
3, 8, 5, 5, 6 sum=27, prod=3600
NOTE special case is 0! Since that will nullify the product this all values should be used +1.
NOTE2
Keep in mind that the idea behind CRC algorithms is to use one byte or dword variable for the total and the variable will eventually overflow.
For example in the case of byte: 250 + 10 = 5, as the byte overflows at 255. However it is okay as both arrays would overflow and the chance for false report is very small. I believe that if we can try hard we can prove it mathematically that is okay.
However, If you lazy to do the math and absolute certainty is required you can use this method quick filtering of all negative candidates and then sort+compare only the positive candidates. Still will be way faster than using only sort+compare.
NOTE3:
Just realized you're using JS and JS is a bit messy with big numbers and doesn't really overflow with arithmetical operations.
However it does overflow with logical operators and the CRC algorithm does use xor so you are good. This is the CRC algo:
https://en.wikipedia.org/wiki/Cyclic_redundancy_check
And this is some open source implemention: https://github.com/emn178/js-crc/blob/master/src/crc.js
On prima vista seems to follow the algorithm, however I am not sure how quality it is, so do your due diligence!
This solution avoids using sort, making the algorithm O(n²), where n is the number of and lengths of the arrays. It has the added benefit of not mutating the arrays and also let's you pass arrays containing any types, not just numbers. It operates by computing a frequency bag for each array item, then assessing whether they all hold the same data. The toBag and bagsEqual functions are both O(n). This makes the main algorithm arraysSame O(n²). Using sort instead of frequency bags would make the solution O(n²log(n)), which isn't nearly as favorable.
function arraysSame(...arrays) {
if(arrays.length < 2) return true;
let bag1 = toBag(arrays[0]);
for(let i = 1; i < arrays.length; i++) {
const bag2 = toBag(arrays[i]);
if(!bagsEqual(bag1, bag2)) return false;
}
return true;
}
function bagsEqual(bag1, bag2) {
if(bag1.size != bag2.size) return false;
for(const [key, value] of bag1) {
if(!bag2.has(key)) return false;
if(value != bag2.get(key)) return false;
}
return true;
}
function toBag(array) {
const bag = new Map();
for(const val of array) {
const count = bag.get(val) || 0;
bag.set(val, count + 1);
}
return bag;
}
I'm wondering if some of you understand how the Fisher-Yates shuffle works and can explain it to me. so I found this Fisher-Yates Shuffle code online:
public function Main() {
var tempArray:Array = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
ShuffleArray(tempArray);
trace(tempArray);
}
public function ShuffleArray(input:Array)
{
for (var i:int = input.length-1; i >=0; i--)
{
var randomIndex:int = Math.floor(Math.random()*(i+1));
var itemAtIndex:Object = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
}
That code works perfectly but I'm still confused
I changed the loop to "input.length" and it doesn't work well, I still got "0" values sometimes. I have no idea why should I use "input.length-1" instead of "input.length"
At the randomize section, why should I randomize the index from 0 to the value (i+1), why don't we just randomize it from 0 to (i) instead?
If some of you understand it, can you please explain it to me?
Thank you so much
Js's array index starts at 0, so array a with length n 's last element is a[n -1].
Math.random return a value from 0 to 0.9999...., but not include 1(range at [0, 1)), so Math.random()* (i + 1), would have a value from 0 to i + 0.999999......, but not i + 1(range [0, i+1)), and use Math.floor to cut the dot parts to get a Integer, so we get a number in range [0, i].
let me explain with an example with negation lets says the array size is 10.
1)if we use index.length line 3 in the for loop will read
input[randomIndex] = input[i] i.e.
input[randomIndex] = input[10];
but since javascript has 0 based arrays ,it has values from index 0 to 9 .index 10 will be out of bounds .Hence we should shuffle from last element(index 9 only)
2)for your second question if we use i instead of i+1.
lets say you are in the 1st iteration of the loop for index 9(will hold true for other iterations also).
Here i is 9 as seen above .we want 9th index to be shuffled from any one of the indices from 0 to 9
Math.random will return from 0 to .999 and Math.floor will lower bound it so in our case,maximum value will be .999 * (9+1) = 9.99 .Math.floor will lower bound it to 9.So range is [0,9]
incase we used i maximum possible value would be 8 i.e, Range[0,8]
Hence we use i+1 since we want values from [0,9]