How to make this fib sequence faster? - javascript

var fibonacci = function(n) {
let cache = {};
let value;
if (n in cache) {
value = cache[n];
} else {
if (n == 0 || n == 1) {
value = n;
} else {
value = fibonacci(n - 1) + fibonacci(n - 2);
cache[n] = value;
}enter code here
}
return value;
};
fibonacci(60)
codewar wont accept this fib sequence its too slow how to make it faster

Put the cache outside of the function, otherwise it won't do anything (subsequent calls of fibonacci, including the recursive calls, won't be able to see prior cached numbers):
let cache = {};
var fibonacci = function(n) {
let value;
if (n in cache) {
value = cache[n];
} else {
if (n == 0 || n == 1) {
value = n;
} else {
value = fibonacci(n - 1) + fibonacci(n - 2);
cache[n] = value;
}
}
return value;
};
console.log(fibonacci(60))
To clean up the code some more, you can immediately return instead, to cut down on indentation and to avoid unnecessary reassignment:
const cache = {};
const fibonacci = function(n) {
if (n in cache) {
return cache[n];
}
if (n <= 1) {
return n;
}
const value = fibonacci(n - 1) + fibonacci(n - 2);
cache[n] = value;
return value;
};
console.log(fibonacci(60))
Keep in mind that this fibonacci will still only be accurate up to a certain point. Once the return value is larger than Number.MAX_SAFE_INTEGER (9007199254740991), it will be inaccurate. If that's a possibility, use and return BigInts instead.

Using two recursion results in very bad perofrmance (good for understanding recursion). You need to use loops and array beside memoization for good performance. After all heavy computation blocks main thread in JavaScript hence not a good choice for heavy computation applications.
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
const cache = [1, 1]
function fibonacci(n) {
if (n <= cache.length) {
return cache[n - 1]
}
for (let i = cache.length; i < n; i++) {
cache[i] = cache[i - 1] + cache[i - 2]
}
return cache[n - 1]
}
To avoid using global you can use closure:
function fibonacci(m) {
const cache = [1, 1]
return (function (n) {
if (n <= cache.length) {
return cache[n - 1]
}
for (let i = cache.length; i < n; i++) {
cache[i] = cache[i - 1] + cache[i - 2]
}
return cache[n - 1]
})(m)
}
This is an example of dynamic programming using recursion and memoization.

Using a loop instead of recursion is faster, and if you use array destructuring it's more readable.
a = fn-1 and b = fn-2
function fibonacci(n) {
if (n === 0) return 0;
if (n === 1) return 1;
let [a, b] = [0, 1];
for (var i = 2; i <= n; i++) {
[a, b] = [b, a + b];
}
return b;
}

Related

Leetcode 4sums concise solution

Recently doing leetcode but encounter difficulties in this 4 sum question. For the kSum function below, I saw some of the solutions online, passing an empty array as a parameter to store the result. I think it makes kSum() too many parameters.
I am thinking of refactoring kSum() holds a parameter of itself but not much process. It return something strange(eg. an empty array)
I would like to ask what I am missing to make my algorithm works? I think the problem may due to the second for loop which loop through kSum(nums, i+1, ...) ?
const fourSum = (nums, target) => {
const sortedNumsArray = nums.sort((a, b) => a - b)
return kSum(sortedNumsArray, 0, 4, target)
}
const kSum = (nums, start, k, target) => {
const result = [];
if( nums.length === start || nums[nums.length - 1] * k < target || nums[start] * k > target) return result;
if (k === 2) {
return twoSum(nums, 0, target)
} else {
let shouldCheck = false;
for (let i = start; i < nums.length; i++) {
if (shouldCheck && nums[i] !== nums[i - 1]) {
for (let set of kSum(nums, i + 1, k - 1, target - nums[i])) {
result.push([nums[i]])
result[result.length - 1].concat(set)
}
}
shouldCheck = true;
}
}
return result;
}
const twoSum = (nums, start, target) => {
let left = start;
let right = nums.length - 1
let subResult = []
while (left < right) {
let sum = nums[left] + nums[right]
if (sum === target) {
subResult.push([nums[left++], nums[right--]])
while (left < right && nums[left] === nums[left + 1]) { left++ }
while (left < right && nums[right] === nums[right - 1]) { right-- }
} else if (sum > target) {
right--
} else {
left++
}
}
return subResult;
}

Finding Fibonacci bugs keep returning undefined

I am trying to solve the fibonacci in recrusive way and I think i got a bug in my code.I can't figurer out where it is.
Example:
fib(4) === 3
function fib(n, array = [0, 1], count = 0) {
if (n == 0) {
return 0;
}
if (n == 1) {
return 1;
}
array.push(array[count] + array[count + 1]);
console.log(array)
if (n === array.length-1) {
return array.pop()
}
fib(n, array, count + 1);
}
let ans=fib(2)
console.log(ans)
you can do by this way using recursion
var i = 0, a = 0, b = 1, c = 0;
var out = "";
function fibonacci(n){
i = 0;
if(i < n){
out += a + ",";
c = a + b;
a = b;
b = c;
i++;
console.log(out);
fibonacci(n - i);
}
}
fibonacci(10);

How to display the numbers in console, without for loop?

the task is to create a recursion, displaying Fibonacci numbers. I need to display the number chain of Fibonacci numbers in the console, without (for) loop.
I have optimised the recursion and displayed the numbers with a (for) loop.
"use strict";
var arr = []
let skkak = function(n)
{
if (n <= 1)
{
return n;
}
if(!isNaN(arr[n])){
return arr[n];
}
else
{
let result = skkak(n - 1) + skkak(n - 2)
arr[n] = result;
return result;
}
}
for(let i=12; i > 0; i--)
{
console.log(skkak(i));
}
no errors
This version is using while (not recursive)
"use strict";
var arr = []
let skkak = function(n)
{
if (n <= 1)
{
return n;
}
if(!isNaN(arr[n])){
return arr[n];
}
else
{
let result = skkak(n - 1) + skkak(n - 2)
arr[n] = result;
return result;
}
}
let i = 12;
while(i > 0)
{
console.log(skkak(i));
i--;
}
Recursive approach
fibonacci = (n) =>
{
if (n===1)
{
return [0, 1];
}
else
{
let s = fibonacci(n - 1);
s.push(s[s.length - 1] + s[s.length - 2]);
return s;
}
};
console.log(fibonacci(5)); // [0,1,1,2,3,5]

How to make a function that returns the factorial of each integer in an array

I'm new to coding and have been given this question that I cannot seem to get right:
Create a function that takes an array of positive integers and returns an array of the factorials of these numbers.
E.g. [4, 3, 2] => [24, 6, 2]
The factorial of a number is the product of that number and all the integers below it.
E.g. the factorial of 4 is 4 * 3 * 2 * 1 = 24
If the number is less than 0, reject it.
The code that I have created is this;
function getFactorials(nums) {
if (nums === 0 || nums === 1)
return 1;
for (var i = nums - 1; i >= 1; i--) {
nums *= i;
}
return nums;
}
The code is being run against this test;
describe("getFactorials", () => {
it("returns [] when passed []", () => {
expect(getFactorials([])).to.eql([]);
});
it("returns one factorial", () => {
expect(getFactorials([3])).to.eql([6]);
});
it("returns multiple factorials", () => {
expect(getFactorials([3, 4, 5])).to.eql([6, 24, 120]);
});
it("returns largest factorials", () => {
expect(getFactorials([3, 8, 9, 10])).to.eql([6, 40320, 362880, 3628800]);
});
});
How should I do this?
First off, make a recursive function that calculates the factorial of a single number:
function factorial(num) {
if (num == 0 || num == 1) {
return 1;
}
return num * factorial(num - 1);
}
Then to do it for an array, just use Array.prototype.map() like so:
function getFactorials(arr) {
var result = arr.map(x => factorial(x));
return result;
}
Here's a demonstration:
function factorial(num) {
if (num == 0 || num == 1) {
return 1;
}
return num * factorial(num - 1);
}
function getFactorials(arr) {
var result = arr.map(x => factorial(x));
return result;
}
console.log(getFactorials([4, 8, 10]));
console.log(getFactorials([]));
console.log(getFactorials([1, 2, 3, 4, 5]));
Hopefully this helps!
You need to separate function into two functions, one for iterating the array and collecting the calculated values and the other to get the facorial of a number.
function getFactorials(nums) {
var result = [],
i;
for (i = 0; i < nums.length; i++) {
result.push(getFactorial(nums[i]));
}
return result;
}
function getFactorial(n) {
if (n === 0 || n === 1) return 1;
return n * getFactorial(n - 1);
}
console.log(getFactorials([]));
console.log(getFactorials([3]));
console.log(getFactorials([3, 4, 5]));
console.log(getFactorials([3, 8, 9, 10]));
This method will take an array of numbers and will return an array of factorial numbers of them,
function getFactorials(array) {
var facArray = [];
for (var j = 0; j < array.length; j++) {
num = array[j];
if (num === 0 || num === 1)
return 1;
for (var i = num - 1; i >= 1; i--) {
num *= i;
}
facArray.push(num);
}
return facArray;
}
console.log(getFactorials([4, 3, 2]));
function getFactorials(nums) {
return numbers = Array.from(nums).map(function factorializeSingleNumber(num) {
if (num == 0 || num == 1) return 1
else return num * factorializeSingleNumber(num - 1)
})
}
The best way I find of tackling these is to break the problem down. So in this case, work a solution that factorializes a single number. When that is working you can add this 'working code' into a map or loop, to work through the array.
My above solution uses recursion but could be a simple 'for loop' too

Array.sort get different result in IOS

it's a simple code, but returns different results in Andriod and Iphone.
var str = [1,2,3,4,5].sort(function () {
return -1;
})
document.write(str);
In MDN(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) it says
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned then the sort order is undefined.
So the result should be 1,2,3,4,5.
But is Iphone it shows 5,4,3,2,1
Here is a link for you to try this code. http://www.madcoder.cn/demos/ios-test.html
And after I did more and more test. I found Iphone is doing a different sorting.
Here is a link shows how sort works: http://www.madcoder.cn/demos/ios-test2.html
The javascript engines use different algorithms for their sort function. Since the compare function doesn't compare values, you get the result of the inner workings of the different algorithms instead of having a sorted result.
Looking at the source code of V8 engine (Chrome) and JavaScriptCore (which seems to be used by Safari, or at least the sort function gives the same result, so I guess it uses the same kind of algorithm), you can view the functions that are being used.
Not that it might not be exactly the functions used, what's important is that the algorithms are different. They give the same result if you actually compare values, but if not, the result is dependent on the way they operate, not on the function itself. At least not completely.
Here's V8 engine sorting function. You'll see that for arrays bigger than 10 elements, the algorithm isn't the same, so the result for arrays smaller than 10 elements is different than for those bigger than 10 elements.
You can find following algorithms here: https://code.google.com/p/chromium/codesearch#chromium/src/v8/src/js/array.js&q=array&sq=package:chromium&dr=C
comparefn = function(a, b) {
return -1
}
var InsertionSort = function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) {
var element = a[i];
for (var j = i - 1; j >= from; j--) {
var tmp = a[j];
var order = comparefn(tmp, element);
if (order > 0) {
a[j + 1] = tmp;
} else {
break;
}
}
a[j + 1] = element;
}
console.log(a);
}
var GetThirdIndex = function(a, from, to) {
var t_array = new InternalArray();
// Use both 'from' and 'to' to determine the pivot candidates.
var increment = 200 + ((to - from) & 15);
var j = 0;
from += 1;
to -= 1;
for (var i = from; i < to; i += increment) {
t_array[j] = [i, a[i]];
j++;
}
t_array.sort(function(a, b) {
return comparefn(a[1], b[1]);
});
var third_index = t_array[t_array.length >> 1][0];
return third_index;
}
var QuickSort = function QuickSort(a, from, to) {
var third_index = 0;
while (true) {
// Insertion sort is faster for short arrays.
if (to - from <= 10) {
InsertionSort(a, from, to);
return;
}
if (to - from > 1000) {
third_index = GetThirdIndex(a, from, to);
} else {
third_index = from + ((to - from) >> 1);
}
// Find a pivot as the median of first, last and middle element.
var v0 = a[from];
var v1 = a[to - 1];
var v2 = a[third_index];
var c01 = comparefn(v0, v1);
if (c01 > 0) {
// v1 < v0, so swap them.
var tmp = v0;
v0 = v1;
v1 = tmp;
} // v0 <= v1.
var c02 = comparefn(v0, v2);
if (c02 >= 0) {
// v2 <= v0 <= v1.
var tmp = v0;
v0 = v2;
v2 = v1;
v1 = tmp;
} else {
// v0 <= v1 && v0 < v2
var c12 = comparefn(v1, v2);
if (c12 > 0) {
// v0 <= v2 < v1
var tmp = v1;
v1 = v2;
v2 = tmp;
}
}
// v0 <= v1 <= v2
a[from] = v0;
a[to - 1] = v2;
var pivot = v1;
var low_end = from + 1; // Upper bound of elements lower than pivot.
var high_start = to - 1; // Lower bound of elements greater than pivot.
a[third_index] = a[low_end];
a[low_end] = pivot;
// From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet.
partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i];
var order = comparefn(element, pivot);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
low_end++;
} else if (order > 0) {
do {
high_start--;
if (high_start == i) break partition;
var top_elem = a[high_start];
order = comparefn(top_elem, pivot);
} while (order > 0);
a[i] = a[high_start];
a[high_start] = element;
if (order < 0) {
element = a[i];
a[i] = a[low_end];
a[low_end] = element;
low_end++;
}
}
}
if (to - high_start < low_end - from) {
QuickSort(a, high_start, to);
to = low_end;
} else {
QuickSort(a, from, low_end);
from = high_start;
}
}
};
InsertionSort([1, 2, 3, 4, 5], 0, 5);
//QuickSort is recursive and calls Insertion sort, so you'll have multiple logs for this one
QuickSort([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 0, 13);
//You'll see that for arrays bigger than 10, QuickSort is called.
var srt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13].sort(function() {
return -1
})
console.log(srt)
And JavaScriptCore uses merge sort. You can find this algorithm here:
http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/builtins/ArrayPrototype.js
function min(a, b) {
return a < b ? a : b;
}
function merge(dst, src, srcIndex, srcEnd, width, comparator) {
var left = srcIndex;
var leftEnd = min(left + width, srcEnd);
var right = leftEnd;
var rightEnd = min(right + width, srcEnd);
for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) {
if (right < rightEnd) {
if (left >= leftEnd || comparator(src[right], src[left]) < 0) {
dst[dstIndex] = src[right++];
continue;
}
}
dst[dstIndex] = src[left++];
}
}
function mergeSort(array, valueCount, comparator) {
var buffer = [];
buffer.length = valueCount;
var dst = buffer;
var src = array;
for (var width = 1; width < valueCount; width *= 2) {
for (var srcIndex = 0; srcIndex < valueCount; srcIndex += 2 * width)
merge(dst, src, srcIndex, valueCount, width, comparator);
var tmp = src;
src = dst;
dst = tmp;
}
if (src != array) {
for (var i = 0; i < valueCount; i++)
array[i] = src[i];
}
return array;
}
console.log(mergeSort([1, 2, 3, 4, 5], 5, function() {
return -1;
}))
Again these may not be exactly the functions used in each browser, but it shows you how different algorithms will behave if you don't actually compare values.

Categories

Resources