I have an array of numbers with 64 indexes (it's canvas image data).
I want to know if my array contains only zero's or anything other than zero.
We can return a boolean upon the first encounter of any number greater than zero (even if the very last index is non-zero and all the others are zero, we should return true).
What is the most efficient way to determine this?
Of course, we could loop over our array (focus on the testImageData function):
// Setup
var imgData = {
data: new Array(64)
};
imgData.data.fill(0);
// Set last pixel to black
imgData.data[imgData.data.length - 1] = 255;
// The part in question...
function testImageData(img_data) {
var retval = false;
for (var i = 0; i < img_data.data.length; i++) {
if (img_data.data[i] > 0) {
retval = true;
break;
}
}
return retval;
}
var result = testImageData(imgData);
...but this could take a while if my array were bigger.
Is there a more efficient way to test if any index in the array is greater than zero?
I am open to answers using lodash, though I am not using lodash in this project. I would rather the answer be native JavaScript, either ES5 or ES6. I'm going to ignore any jQuery answers, just saying...
Update
I setup a test for various ways to check for a non-zero value in an array, and the results were interesting.
Here is the JSPerf Link
Note, the Array.some test was much slower than using for (index) and even for-in. The fastest, of course, was for(index) for(let i = 0; i < arr.length; i++)....
You should note that I also tested a Regex solution, just to see how it compared. If you run the tests, you will find that the Regex solution is much, much slower (not surprising), but still very interesting.
I would like to see if there is a solution that could be accomplished using bitwise operators. If you feel up to it, I would like to see your approach.
Your for loop is the fastest way on Chrome 64 with Windows 10.
I've tested against two other options, here is the link to the test so you can run them on your environment.
My results are:
// 10776 operations per second (the best)
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== 0) {
break
}
}
// 4131 operations per second
for (const n of arr) {
if (n !== 0) {
break
}
}
// 821 operations per second (the worst)
arr.some(x => x)
There is no faster way than looping through every element in the array. logically in the worst case scenario the last pixel in your array is black, so you have to check all of them. The best algorithm therefore can only have a O(n) runtime. Best thing you can do is write a loop that breaks early upon finding a non-white pixel.
Related
I implemented a simple algorithm in 2 ways. One using indexOf and other one using Hash Table.
The problem:
Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false.
First one. Is it Time Complexity O(N^2) because I have N letters in the ransomNote and I can do N searches in the indexOf?
var canConstruct = function(ransomNote, magazine) {
if(magazine.length < ransomNote.length) return false;
const arr = magazine.split("");
for(let i=0; i<ransomNote.length; i++) {
if(arr.indexOf(ransomNote[i]) < 0)
return false;
const index = arr.indexOf(ransomNote[i]);
arr.splice(index, 1);
}
return true;
};
Second one. What is the time complexity? Does the hash table makes it O(N)?
var canConstruct = function(ransomNote, magazine) {
if(magazine.length < ransomNote.length) return false;
const map = new Map();
for(let i =0; i<magazine.length; i++) {
if(map.has(magazine[i]))
map.set(magazine[i], map.get(magazine[i])+1);
else
map.set(magazine[i], 1);
}
for(let i=0; i<ransomNote.length; i++) {
if(!map.has(ransomNote[i]))
return false;
else {
const x = map.get(ransomNote[i]) - 1;
if(x > 0)
map.set(ransomNote[i], x)
else
map.delete(ransomNote[i]);
}
}
return true;
};
Thanks
FIRST solution
Well one thing you have to take in consideration, especially in the first solution is that split, slice and indexOf methods all have their own time complexity.
Let's say you have m letters in magazine. When you split it into array, you will already use O(m) time complexity there (and of course O(m) space complexity due to the fact you store it all in a new array, that has a size of m).
Now you enter a for loop that will run n times (where n is the number of letters in ransomNote). So right then and there you have O(m * n) time complexity. indexOf operation will also be called n times with the caveat that it runs O(m) every time it's called. You can see there how quickly you start adding up your time complexity.
I see it being like O(3 * m * n^2) which rounds up to O(m * n^n) time complexity. I would strongly suggest not calling indexOf multiple times, just call it once and store its result somewhere. You will either have an index or -1 meaning it wasn't found.
SECOND solution
Much better. Here you populate a hash map (so some extra memory used, but considering you also used a split in first, and stored it, it should roughly be the same).
And then you just simply go with one loop over a randomNote and find a letter in the hashMap. Finding a letter in map is O(1) Time so it's really useful for this type of algorithm.
I would argue the complexity would be O(n * m) in the end so much better than the first one.
Hope I made sense to you. IF you want we can dive a bit deeper in space analysis later in the comments if you respond
The version with indexOf() is O(N*M), where N is the length of the ransom note, and M is the length of the magazine. You perform up to N searches, and each search is linear through the magazine array that's N characters. Also, array.splice() is O(M) because it has to copy all the array elements after index to the lower index.
Hash table access and updates are generally considered to be O(1). The second version performs N hash table lookups and updates, so the overall complexity is O(N).
I would like to return all possible combinations for a string while maintaining the proper order of everything and avoiding duplicates. The reason for this? I'd like to make answers for some Japanese quizzes more flexible by allowing a mix of kana and kanji. As such, I require all possible combinations for comparison against the user's answer.
This is the current syntax of the function: (located here)
Genki.getAlts('{月曜日}と{水曜日}と{金曜日}に{日本語}のクラスがあります', 'げつようび|すいようび|きんようび|にほんご');
The text within curly braces is the text that will be replaced by the alternative text in the second argument, I'll refer to these simply as replacements. HOWEVER, the alternate text should ONLY replace the same index. That is:
月曜日 can only be replaced with げつようび
水曜日 can only be replaced with すいようび
and so on...
To give a simple example of what I'd like to achieve. Say I have the following:
Genki.getAlts('...{A}...{B}...', '1|2', true);
I'd like it to return all combinations, such as below.
'...1...{B}...'
'...1...2...'
'...{A}...2...'
'...{A}...{B}...'
The current implementation works well with 2-7 given replacements, but when given more than 8, the total combo coverage begins to drop. The total amount of combinations can be calculated using this formula: Math.pow(2, 8), which would return "256" combinations for 8 replacements, but currently getAlts() is only returning 234 combos, which means we're missing 22, only giving us 91% combo coverage.
So that is where I'm currently stuck. You can review the current code via the links below. (and yes, it's rather hackish) Being self-taught I tried my best to get as many combos as possible, but I'm afraid that my skill with mathematics isn't that good. I'm sure there's a much simpler way of going about this and I'm just overthinking it.
code: Genki.getAlts()
test page: lesson-4/workbook-6 || page source (the console will show all current combinations)
As an example of the current algorithm's failure, open your console, and you should see a warning for the last problem, saying something along the lines of:
234/256 (91.40625% combo coverage for 8 replacements; 22 missing combos
Code for this problem:
Genki.getAlts('{1:私}はきのう{学校}で{1:写真}を{1:撮}りました。{2:私}は{家}でも{2:写真}を{2:撮}りました。', 'わたし|がっこう|しゃしん|と|わたし|いえ|しゃしん|と', true);
and a much simpler one with 10 replacements for performing test cases in the console:
Genki.getAlts('{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}', '1|2|3|4|5|6|7|8|9|10', true)
Is there any possible and simplistic way of returning all the combinations for a string regardless of how many replacements are specified? While I do know how many combinations there are, using Math.pow(2, n), I'm unsure of how to properly get them all.
I am open to hearing about existing algorithms or frameworks for achieving this.
PS: as things are, the algorithm works fine for 2-7 replacements, with very few problems ever reaching or going above this threshold. However, when they do, there's a chance that the user's answer will erroneously be marked wrong and I'd like to avoid this. The simplest solution would obviously be to avoid ever breaking 7, but that's not always possible, and furthermore, the current way I'm achieving this isn't optimal, so I would like to optimize it as well.
You can solve this problem using binary math. Here's an approach that generates the array of strings:
function getAlts(str, alt) {
var subs = alt.split('|');
var length = subs.length;
var permutations = Math.pow(2, length);
var results = [];
for (var i = 0; i < permutations; ++i) {
var bitIndex = 0;
var result = str.replace(/\{(.*?)\}/g, function (match, p1) {
var subIndex = bitIndex++;
var bit = length - 1 - subIndex;
return ((1 << bit) & i) ? subs[subIndex] : p1;
});
results.push(result);
}
return results;
}
console.log(getAlts('...{A}...{B}...', '1|2'));
Or if you're able to use ES6 (ECMAScript 2015), you can write a generator function to use less memory:
function* getAlts(str, alt) {
var subs = alt.split('|');
var length = subs.length;
var permutations = Math.pow(2, length);
for (var i = 0; i < permutations; ++i) {
var bitIndex = 0;
var result = str.replace(/\{(.*?)\}/g, function (match, p1) {
var subIndex = bitIndex++;
var bit = length - 1 - subIndex;
return ((1 << bit) & i) ? subs[subIndex] : p1;
});
yield result;
}
}
var results = getAlts('{A}{B}{C}{D}{E}{F}{G}{H}{I}', '1|2|3|4|5|6|7|8|9');
var total = 0;
for (var result of results) {
console.log(result);
total++;
}
console.log('total:', total);
Can someone tell me what type of sorting is this? Is this still O(n) even after adding the filter?
const sortMe = arr => {
let sorted = new Array(arr.length).fill(0);
for(let i = 0; i < sorted.length; i++){
if(sorted.indexOf(arr[i]) === -1)
sorted[arr[i] - 1] = arr[i];
else sorted.splice(sorted.indexOf(arr[i]), 0, arr[i]);
}
return sorted.filter(x => x !== 0);
}
console.log(sortMe([3,15,2,1,18,2,5,6,7,12,3,1,2,3]))
Sorry for asking this, I'm not a computer science graduate.
That's O(n)^2.
First, you are going through the loop:
for(let i = 0; i < sorted.length; i++){
That makes it O(n) automatically without adding any processing. Then, in addition to that, you're also using indexOf (in both branches).
sorted.splice(sorted.indexOf(arr[i]), 0, arr[i]);
indexOf starts with the first element and then moves to each element stepwise until it reaches the sought element. So, for each step in O(n), you are calling a function which iterates over the entire list, this means you are calling O(n), n times, making it O(n*n), or O(n^2).
Note: you might not think it is O(n^2) because you are processing a subset of the list for indexOf. However, the average case is still looking at a list of length n/2.
You also asked about adding a filter function. This might make it seem like it should be O(n^2 + n).
For big-O notation, you remove all constants: O-notation is about complexity and growth of equations with larger inputs. Therefore it's either "constant, logarithmic, linear, exponential, factorial, etc", not "Factorial + logarithmic."
I was attempting this Codewars challenge and the problem involves finding the divisors of a number and then calculating the sum of these divisors squared. I found two approaches to this problem.
The first approach is based on another Stackoverflow questions about finding the sum of all divisors and seems clever at first:
function divisorsSquared(n) {
// create a numeric sequence and then reduce it
return [...Array(n+1).keys()].slice(1)
.reduce((sum, num)=>sum+(!(n % (num)) && Math.pow(num,2)), 0);
}
The second approach I used was using a simple for-loop:
function divisorsSquared(n) {
var sum = 0;
for(var i = 1; i<= n; i++){
if(n % i === 0) sum += Math.pow(i,2);
}
return sum;
}
Now I noticed that the first approach is significantly slower than the second and a quick jsperf test confirms this.
My questions are: Why is the first approach so much slower and what approach is preferable in production code?
On Codewars I notice that for many challenges there are clever one-line solutions using similar array methods. As a beginner, may such solutions be considered better practice than for-loops, even if performance is worse?
Array(n+1) allocates an array with n + 1 elements, Array(n+1).keys() returns an iterator over the created array's indices, but the spread operator [...Iterator] helps "unwrap" this iterator into yet another array, then finally slice(1) comes along to copy the secondly created array starting at index 1 which allocates yet another array (third one) with the number 0 discarded. So that were 3 allocations but 2 were dicarded. Your for-loop does not allocate any arrays, it is a simple traversal in O(n) with only 2 allocations for i and sum, so it is more efficient
sum+(!(n % (num)) && Math.pow(num,2)) is essentially the same as if(n % i === 0) sum += Math.pow(i,2); but the if approach is way more readable. If I were the judge, I would pick the second approach because it is more memory efficient, yet it favors readability.
Looking into the code, for loop is obviously less complex and more readable.
Consider you are working within a team, maximum number of your team members will know what the code is doing right away.
Some will have to look up what the reduce() method is, but then they'll also know what's going on.
So here, a for loop is easier for others to read and understand.
On the other side, native array functions (filter(), map(), reduce()) will save you from writing some extra code
and also slower in performance.
For a beginner, I think for-loops should be better over native array functions.
Functional or imperative approaches makes a difference in JS. Imperative always wins.
Yet, the real thing is most of time a better algorithm is the winner. Your code is a naive approach. You can tune it to work much better just by checking the integers up until the square root of the target value and you will get two answers per check. If target is 100 if 2 is a dividend then 100/2 must be a dividend too.. So it's fair to check up to Math.sqrt(100) - 1 and handle 10 with care in order to not consider it twice.
Accordingly now the functional solution with reduce beats the imperative naive solution.
function divisorsSquared(n) {
var sn = Math.sqrt(n);
return Array.from({length:~~sn-1},(_,i) => i+1)
.reduce((s,m) => n%m ? s : s + m*m + (n/m)*(n/m), 0) + (n%sn ? 0 : sn*sn);
}
var result = 0;
console.time("functional and tuned");
result = divisorsSquared(1000000);
console.timeEnd("functional and tuned");
console.log("for input: 1000000 the result is:",result);
function dvssqr(n) {
var sum = 0;
for(var i = 1; i<= n; i++){
if(n % i === 0) sum += Math.pow(i,2);
}
return sum;
}
console.time("imperative and naive");
result = dvssqr(1000000);
console.timeEnd("imperative and naive");
console.log("for input: 1000000 the result is:",result);
I have made a little test, and found out that array.sort(function(a, b) { return a - b; }); is a lot faster than array.sort(); in JavaScript.
The results were quite shocking, about 1.7 times faster in IE9, 1.6 times in FF7 and 6.7 times in Chrome.
Also, by implementing quicksort by myself in JS, I found it was even faster than both methods mentioned above.
(Two different implementations, one accepts a comparer function as a parameter, the other doesn't. Both were faster.)
Is there any reasonable explanation?
EDIT: My implementations:
No comparer:
function quickSort(array, from, to) {
if(typeof from === 'undefined') {
from = 0;
to = array.length - 1;
}
else if(typeof to === 'undefined') {
to = array.length - 1;
}
if(to - from < 1) {
return;
}
var i = from, pivot = to, t;
while(i < pivot) {
if(array[i] > array[pivot]) {
t = array[i];
array[i] = array[pivot - 1];
array[pivot - 1] = array[pivot];
array[pivot] = t;
pivot--;
}
else {
i++;
}
}
quickSort(array, from, pivot - 1);
quickSort(array, pivot + 1, to);
}
With comparer:
function quickSortFunc(array, sortfunc, from, to) {
if(typeof from === 'undefined') {
from = 0;
to = array.length - 1;
}
else if(typeof to === 'undefined') {
to = array.length - 1;
}
if(to - from < 1) {
return;
}
var i = from, pivot = to, t;
while(i < pivot) {
if(sortfunc(array[i], array[pivot]) > 0) {
t = array[i];
array[i] = array[pivot - 1];
array[pivot - 1] = array[pivot];
array[pivot] = t;
pivot--;
}
else {
i++;
}
}
quickSortFunc(array, sortfunc, from, pivot - 1);
quickSortFunc(array, sortfunc, pivot + 1, to);
}
There's two factors that come into play:
First, as Felix King mentioned in the comments, the native sort method converts each array member to a string before comparing. Using function(a, b) { return a - b; } is way faster if all (or most) array members are numbers.
Second, the sorting algorithm is implementation dependent. As you may or may not know, quicksort performs really bad if you insert a new element into an already sorted array. Maybe that's why WebKit decided to implement Selection Sort instead.
But fear not, help is near! Somebody already forked WebKit to fix this
Many reasons would come into play. Not having to check variable type is one of them and only one of them. And your implementation makes the optimiser happy. It works with dense array, it works only with numbers, the variables are well scoped and reused. No this, no with, no eval, no magic variables, properties, functions, or types. It would optimise well.
However, if you have tried to implement type-idependent, order-independent array methods such as reverse() you may also find that your own implementation is faster. At least mine is.
Why?
JavaScript is heavily optimised nowadays, espcially on loops and repeated operations on same type of stuffs - number, string, even objects of same shape (it's complicated). In extreme cases the runtime would inline your functions, would skip variable type checks, and, in case of Chrome, would even keep your numbers in registries so that your loop can be as fast as C.
Wow.
But these optimisations only took off in recent years. At this moment, native functions are not yet as optimisable as user code. They don't undergo as much dynamic optimisations as user code do.
There, I said it.
Currently, user code may run faster then native implementation, espcially since the programmer knows what data flow in it. But this can be temporary.
I'll stop here and let you decide whether you want to create your own array library. ;)
This is quite a wild guess, but could the performance hit occur due to the native sort, checking if the attributes passed is blank or null... Hence searching up the default function on each search (instead of once)...
It could be a mistaken optimization issue, that could be resolved if true... Hopefully someone in firefox dev can answer this :)