Check equality between N > 2 arrays with maximum performance? - javascript

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;
}

Related

Can anyone explain recursive in Nth fibonacci?

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.

Determine if product of integers is even or odd in javascript

I am trying to determine if the product of all the integers is even or odd.
I have a list of integers, and I want to check if the product of the integers is even or odd.
For example:
determineIfEvenOrOdd([6,7,9,9])
function determineIfEvenOrOdd(int_array) {
//Code here
}
I was thinking of looping through the array and multiplying the numbers to find out the product of the array integers. But then I thought it would be expensive to do this if the array was huge.
I am a beginner, and would like to know a possible approach for the solution.
If your list of numbers contains an even number, the product of all numbers will be even.
You can loop through the list of numbers and check each individual number for even-ness with a conditional statement like:
// Put this code inside function determineIfEvenOrOdd
var even = false;
for (let i=0; i<int_array.length; i++) {
if (i%2==0) {
even = true;
break;
}
}
An efficient way would be to check whether there is any number that is even, if so, the product is even. If there aren't any numbers that are even, then the product is odd.
function isProductEven(arr)
{
for (let i = 0; i < arr.length; i++)
if ((arr[i] & 1) === 0) return true;
return false;
}
console.log(isProductEven([6, 7, 9, 9]))
This outputs true as the product of these numbers is even.
The most concise solution would be this:
const isProductEven = arr =>
arr.some(e=>!(e%2));
This checks if at least one of the numbers in the array is even by testing if its remainder from division by 2 equals to 0. You can use it directly as well:
console.log([1,2,3].some(e=>!(e%2))); // true
console.log([1,3,5].some(e=>!(e%2))); // false
console.log([].some(e=>!(e%2))); // false
I usually implement Array.reduce to achieve this. It's easy to implement.
function isArrayProductEven(arr) {
return !(arr.reduce((a, b) => a * b, 1) % 2);
}
console.log(isArrayProductEven([1,2,3,4,5]));
console.log(isArrayProductEven([1,3,5,7,9]));
How this works is: multiply all numbers in the array and check the remainder of 2 (odd / even) to determine if the result is odd (false) or even (true).

Explanation of .sort in JavaScript [duplicate]

How does the following code sort this array to be in numerical order?
var array=[25, 8, 7, 41]
array.sort(function(a,b){
return a - b
})
I know that if the result of the computation is...
Less than 0: "a" is sorted to be a lower index than "b".
Zero: "a" and "b" are considered equal, and no sorting is performed.
Greater than 0: "b" is sorted to be a lower index than "a".
Is the array sort callback function called many times during the course of the sort?
If so, I'd like to know which two numbers are passed into the function each time. I assumed it first took "25"(a) and "8"(b), followed by "7"(a) and "41"(b), so:
25(a) - 8(b) = 17 (greater than zero, so sort "b" to be a lower index than "a"): 8, 25
7(a) - 41(b) = -34 (less than zero, so sort "a" to be a lower index than "b": 7, 41
How are the two sets of numbers then sorted in relation to one another?
Please help a struggling newbie!
Is the array sort callback function called many times during the course of the sort?
Yes
If so, I'd like to know which two numbers are passed into the function each time
You could find out your self with:
array.sort((a,b) => {
console.log(`comparing ${a},${b}`);
return a > b ? 1
: a === b ? 0
: -1;
});
EDIT
This is the output I've got:
25,8
25,7
8,7
25,41
The JavaScript interpreter has some kind of sort algorithm implementation built into it. It calls the comparison function some number of times during the sorting operation. The number of times the comparison function gets called depends on the particular algorithm, the data to be sorted, and the order it is in prior to the sort.
Some sort algorithms perform poorly on already-sorted lists because it causes them to make far more comparisons than in the typical case. Others cope well with pre-sorted lists, but have other cases where they can be "tricked" into performing poorly.
There are many sorting algorithms in common use because no single algorithm is perfect for all purposes. The two most often used for generic sorting are Quicksort and merge sort. Quicksort is often the faster of the two, but merge sort has some nice properties that can make it a better overall choice. Merge sort is stable, while Quicksort is not. Both algorithms are parallelizable, but the way merge sort works makes a parallel implementation more efficient, all else being equal.
Your particular JavaScript interpreter may use one of those algorithms or something else entirely. The ECMAScript standard does not specify which algorithm a conforming implementation must use. It even explicitly disavows the need for stability.
Pairs of values are compared, one pair at a time. The pairs that are compared are an implementation detail--don't assume they will be the same on every browser. The callback can be anything (so you can sort strings or Roman numerals or anything else where you can come up with a function that returns 1,0,-1).
One thing to keep in mind with JavaScript's sort is that it is not guaranteed to be stable.
Deeply Knowledge
If the result is negative a is sorted before b.
If the result is positive b is sorted before a.
If the result is 0 no changes are done with the sort order of the two values.
NOTE:
This code is the view inside of the sort method step by step.
OUTPUT:
let arr = [90, 1, 20, 14, 3, 55];
var sortRes = [];
var copy = arr.slice(); //create duplicate array
var inc = 0; //inc meant increment
copy.sort((a, b) => {
sortRes[inc] = [ a, b, a-b ];
inc += 1;
return a - b;
});
var p = 0;
for (var i = 0; i < inc; i++) {
copy = arr.slice();
copy.sort((a, b) => {
p += 1;
if (p <= i ) {
return a - b;
}
else{
return false;
}
});
p = 0;
console.log(copy +' \t a: '+ sortRes[i][0] +' \tb: '+ sortRes[i][1] +'\tTotal: '+ sortRes[i][2]);
}
To help clarify the behavior of Array#sort and its comparator, consider this naive insertion sort taught in beginning programming courses:
const sort = arr => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && arr[j-1] > arr[j]; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array);
console.log("" + array);
Ignoring the choice of insertion sort as the algorithm, focus on the hardcoded comparator: arr[j-1] > arr[j]. This has two problems relevant to the discussion:
The > operator is invoked on pairs of array elements but many things you might want to sort such as objects don't respond to > in a reasonable way (the same would be true if we used -).
Even if you are working with numbers, oftentimes you want some other arrangement than the ascending sort that's been baked-in here.
We can fix these problems by adding a comparefn argument which you're familiar with:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array, (a, b) => a - b);
console.log("" + array);
sort(array, (a, b) => b - a);
console.log("" + array);
const objArray = [{id: "c"}, {id: "a"}, {id: "d"}, {id: "b"}];
sort(objArray, (a, b) => a.id.localeCompare(b.id));
console.log(JSON.stringify(objArray, null, 2));
Now the naive sort routine is generalized. You can see exactly when this callback is invoked, answering your first set of concerns:
Is the array sort callback function called many times during the course of the sort? If so, I'd like to know which two numbers are passed into the function each time
Running the code below shows that, yes, the function is called many times and you can use console.log to see which numbers were passed in:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
console.log("on our version:");
const array = [3, 0, 4, 5];
sort(array, (a, b) => console.log(a, b) || (a - b));
console.log("" + array);
console.log("on the builtin:");
console.log("" +
[3, 0, 4, 5].sort((a, b) => console.log(a, b) || (a - b))
);
You ask:
How are the two sets of numbers then sorted in relation to one another?
To be precise with terminology, a and b aren't sets of numbers--they're objects in the array (in your example, they're numbers).
The truth is, it doesn't matter how they're sorted because it's implementation-dependent. Had I used a different sort algorithm than insertion sort, the comparator would probably be invoked on different pairs of numbers, but at the end of the sort call, the invariant that matters to the JS programmer is that the result array is sorted according to the comparator, assuming the comparator returns values that adhere to the contract you stated (< 0 when a < b, 0 when a === b and > 0 when a > b).
In the same sense that I have the freedom to change my sort's implementation as long as I don't breach my specification, implementations of ECMAScript are free to choose the sort implementation within the confines of the language specification, so Array#sort will likely produce different comparator calls on different engines. One would not write code where the logic relies on some particular sequence of comparisons (nor should the comparator produce side effects in the first place).
For example, the V8 engine (at the time of writing) invokes Timsort when the array is larger than some precomputed number of elements and uses a binary insertion sort for small array chunks. However, it used to use quicksort which is unstable and would likely give a different sequence of arguments and calls to the comparator.
Since different sort implementations use the return value of the comparator function differently, this can lead to surprising behavior when the comparator doesn't adhere to the contract. See this thread for an example.
Is the array sort callback function called many times during the course of the sort?
Yes, that's exactly it. The callback is used to compare pairs of elements in the array as necessary to determine what order they should be in. That implementation of the comparison function is not atypical when dealing with a numeric sort. Details in the spec or on some other more readable sites.
Is the array sort callback function called many times during the course of the sort?
Since this is a comparison sort, given N items, the callback function should be invoked on average (N * Lg N) times for a fast sort like Quicksort. If the algorithm used is something like Bubble Sort, then the callback function will be invoked on average (N * N) times.
The minimum number of invocations for a comparison sort is (N-1) and that is only to detect an already sorted list (i.e. early out in Bubble Sort if no swaps occur).
Is the array sort callback function called many times during the course of the sort?
Yes
If so, I'd like to know which two numbers are passed into the function each time.
a: The first element for comparison.
b: The second element for comparison.
In the following example, a will be "2" and b will be "3" in the first iteration
How are the two sets of numbers then sorted in relation to one another?
Elements are sorted according to the return value of the compare function.
greater than 0: sort a after b
less than 0: sort a before b
equal to 0: keep original order of a and b
Here is an example
var arr = [3, 2, 1, 5, 4, 6, 7, 9, 8, 10];
console.log(arr.sort((a, b) => {
console.log(a - b, a, b);
//b-a if sorting in decending order
return a - b;
}));

how to check if an element is present in an array or not in javascript without using for loop or any method of array

How to check if an element is present in an array or not in JavaScript without using for loop or any method of array like map, reduce?
let numList= [1,2,3,6,9,2,-8,20]; I want to check for 9 and 30, if it exists or not without using for loop or any array method
I suppose one option would be to convert the array to a Set and check Set.has:
let numList= [1,2,3,6,9,2,-8,20];
const set = new Set(numList);
console.log(set.has(9));
console.log(set.has(30));
Checking whether a Set has an element has complexity of O(1), which is lower complexity than any of the array methods or for loops, which are O(N) or O(log N), so when you have a very large array and you want to check whether it has certain elements, converting it to a Set first can be a good idea.
You can convert the array to string using JSON.stringify and use String includes to check if the string contains the specific searched value
let numList = [1, 2, 3, 6, 9, 2, -8, 20];
let m = JSON.stringify(numList)
console.log(m.includes(-8))
If you can use a while loop you may be able to implement a binary search. Since it was for an interview question I wouldn't be surprised if this is along the lines of what they were looking for.
Here is the traditional algorithm in psuedocode, borrowed from Rosetta Code
BinarySearch(A[0..N-1], value) {
low = 0
high = N - 1
while (low <= high) {
// invariants: value > A[i] for all i < low
value < A[i] for all i > high
mid = (low + high) / 2
if (A[mid] > value)
high = mid - 1
else if (A[mid] < value)
low = mid + 1
else
return mid
}
return not_found // value would be inserted at index "low"
}

javascript: how to make function run faster

so i have to write a function which meets the following requirements:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
Example:
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) = false;
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) = true.
You can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
Input/Output
[time limit] 4000ms (js)
[input] array.integer sequence
Guaranteed constraints:
2 ≤ sequence.length ≤ 105,
-105 ≤ sequence[i] ≤ 105.
so my code works except for one problem--there are 30 tests it has to pass with the time constraint of 4000ms, but it always times out on the 30th test, every time. i have tried modifying it so that it runs faster, but each time i do so it no longer works correctly. although i technically only have to write one function, i broke it up into three separate functions. here's my code:
var greater = function(a, b) {
if (a < b) {
return true
} else {
return false
}
}
function greaterThan(arr) {
for (var i = 0; i < arr.length-1; i++) {
var curr = arr[i]
var next = arr[i + 1]
if (greater(curr, next) === false) {
return false
}
}
return true
}
function almostIncreasingSequence(sequence) {
for(var i = 0; i < sequence.length; i++) {
var newArr = sequence.slice()
newArr.splice(i, 1)
if (greaterThan(newArr) === true) {
return true
}
}
return false
}
so how can i make it run faster without using two for-loops/iterations to do this?
Improving the algorithm may bring better results than improving the code. Here's the problem:
If the sequence is not strictly increasing at index i, such that a[i]>=a[i+1] is true, either a[i] or a[i+1] must be removed to possibly make the array strictly increasing - they can't both be left in place.
If the input array is to be fixable by removing only one element, and it decreases after the ith element it must become strictly increasing by removing the element with subscript i or (i+1).
Compare the efficiency of checking the original array and at most two sub arrays before returning true or false, with checking the same number of arrays as the original array's length. I'll leave re-writing the code to you - it's not my homework :-)

Categories

Resources