It was going so well. I thought I had my head around time complexity. I was having a play on codility and used the following algorithm to solve one of their problems. I am aware there are better solutions to this problem (permutation check) - but I simply don't understand how something without nested loops could have a time complexity of O(N^2). I was under the impression that the associative arrays in Javascript are like hashes and are very quick, and wouldn't be implemented as time-consuming loops.
Here is the example code
function solution(A) {
// write your code in JavaScript (Node.js)
var dict = {};
for (var i=1; i<A.length+1; i++) {
dict[i] = 1;
}
for (var j=0; j<A.length; j++) {
delete dict[A[j]];
}
var keyslength = Object.keys(dict).length;
return keyslength === 0 ? 1 : 0;
}
and here is the verdict
There must be a bug in their tool that you should report: this code has a complexity of O(n).
Believe me I am someone on the Internet.
On my machine:
console.time(1000);
solution(new Array(1000));
console.timeEnd(1000);
//about 0.4ms
console.time(10000);
solution(new Array(10000));
console.timeEnd(10000);
// about 4ms
Update: To be pedantic (sic), I still need a third data point to show it's linear
console.time(100000);
solution(new Array(100000));
console.timeEnd(100000);
// about 45ms, well let's say 40ms, that is not a proof anyway
Is it possible to have quadratic time complexity without nested loops? Yes. Consider this:
function getTheLengthOfAListSquared(list) {
for (var i = 0; i < list.length * list.length; i++) { }
return i;
}
As for that particular code sample, it does seem to be O(n) as #floribon says, given that Javascript object lookup should be constant time.
Remember that making an algorithm that takes an arbitrary function and determines whether that function will complete at all is provably impossible (halting problem), let alone determining complexity. Writing a tool to statically determine the complexity of anything but the most simple programs would be extremely difficult and this tool's result demonstrates that.
Related
Is it safe to assume that array.indexOf() does a linear search from the beginning of the array?
So if I often search for the biggest value, will sorting the array before calling indexOf make it run even faster?
Notes:
I want to sort only once and search many times.
"biggest value" is actually the most popular search key which is a string.
Yes, indexOf is starting from the first to the last. Sorting it before asking the first entry afterwards makes a difference in performance depending in the performance of sorting algorithm. Normally O(N log N) in quicksort to O(n) in linear search. I would suggest you to make a simple test for it with random value count and see how performance behave.
Of course it depends on your DataObject:
ArrayList:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
Perhaps a TreeSet can also help you till its ordered all the time.
At the end i would say:"Depends on your data-container and how the ordering or search is implemented and where the performance in the whole process is needed".
As a comment say with pure arrays you can make binarySearch which has the same performance impact of quicksort.
So at the end its not only a question of the performance of algorithm but also at what time you need the performance in the process. For example if you have lots of time by adding values and no time by getting the value you need, a sorted structure can improve it very well, like Tree-Collections. If you need more performance by adding things its perhaps the other way around.
I'm messing around with the performances of JavaScript's push and pop functions.
I have an array called arr.
When I run this:
for (var i = 0; i < 100; i++) {
for (var k = 0; k < 100000; k++) {
arr.push(Math.ceil(Math.random() * 100));
arr.pop();
}
}
I get a time of 251.38515999977244 Milliseconds (I'm using performance.now() function).
But when I run a custom push and pop:
Array.prototype.pushy = function(value) {
this[this.length] = value;
}
Array.prototype.poppy = function() {
this.splice(-1, 1);
}
for (var i = 0; i < 100; i++) {
for (var k = 0; k < 100000; k++) {
arr.pushy(Math.ceil(Math.random() * 100));
arr.poppy();
}
}
The time is 1896.055750000014 Milliseconds.
Can anyone explain why there's such a huge difference between these?
To those who worry about time difference. I ran this test 100 times and computed an average time. I did that 5 times to ensure there weren't any outlying times.
Because the built-in function is written is whatever language the browser was written in (probably C++) and is compiled. The custom function is written in Javascript and is interpreted.
Generally interpreted languages are much slower than compiled ones. One usually doesn't notice this with Javascript because for the most part, you only execute a couple lines of JS between human interactions (which is always the slowest part).
Running JS in a tight loop as your done here, highlights the difference.
The reason is that the built-in function was specifically designed and optimized to perform a specific function. The browser takes whatever shortcuts possible when using the built-in function that it may not be as quick to recognize in the custom function. For example, with your implementation, the function needs to get the array length every single time the function is called.
Array.prototype.pushy = function(value) {
this[this.length] = value;
}
However, by simply using Array.prototype.push, the browser knows that the purpose is to append a value on to the array. While browsers may implement the function differently, I highly doubt any needs to compute the length of the array for every single iteration.
My question somehow relates to this, but it still involves some key differences.
So here it is, I have following code;
for(var i = 0; i < someObj.children[1].listItems.length; i++)
{
doSomething(someObj.children[1].listItems[i]);
console.log(someObj.children[1].listItems[i]);
}
vs.
var i = 0,
itemLength = someObj.children[1].listItems.length,
item;
for(; i < itemLength; i++)
{
item = someObj.children[1].listItems[i];
doSomething(item);
console.log(item);
}
Now this is a very small exemplary part of code I deal with in an enterprise webapp made in ExtJS. Now here in above code, second example is clearly more readable and clean compared to first one.
But is there any performance gain involved when I reduce number of object lookups in similar way?
I'm asking this for a scenario where there'll be a lot more code within the loop accessing members deep within the object and iteration itself would be happening ~1000 times, and browser varies from IE8 to Latest Chrome.
There won't be a noticeable difference, but for performance and readability, and the fact that it does look like a live nodeList, it should probably be iterated in reverse if you're going to change it :
var elems = someObj.children[1].listItems;
for(var i = elems.length; i--;) {
doSomething(elems[i]);
console.log(elems[i]);
}
Performance gain will depend on how large the list is.
Caching the length is typically better (your second case), because someObj.children[1].listItems.length is not evaluated every time through the loop, as it is in your first case.
If order doesn't matter, I like to loop like this:
var i;
for( i = array.length; --i >= 0; ){
//do stuff
}
Caching object property lookup will result in a performance gain, but the extent of it is based on iterations and depth of the lookups. When your JS engine evaluates something like object.a.b.c.d, there is more work involved than just evaluating d. You can make your second case more efficient by caching additional property lookups outside the loop:
var i = 0,
items = someObj.children[1].listItems,
itemLength = items.length,
item;
for(; i < itemLength; i++) {
item = items[i];
doSomething(item);
console.log(item);
}
The best way to tell, of course, is a jsperf
I am currently doing program 2 for the startup engineering course offered on coursera
I'm programming using and ubuntu instance using Amazon web services and my programming is constantly hanging. There might be something wrong with my node.js program but I can't seem to locate it.
This program is meant to produce the first 100 Fibonacci numbers separated with commas.
#! /usr/bin/env node
//calculation
var fibonacci = function(n){
if(n < 1){return 0;}
else if(n == 1 || n == 2){return 1;}
else if(n > 2){return fibonacci(n - 1) + fibonacci(n-2);}
};
//put in array
var firstkfib = function(k){
var i;
var arr = [];
for(i = 1; i <= k; i++){
arr.push(fibonacci(i));
}
return arr
};
//print
var format = function(arr){
return arr.join(",");
};
var k = 100;
console.log("firstkfib(" + k +")");
console.log(format(firstkfib(k)));
The only output I get is
ubuntu#ip-172-31-30-245:~$ node fib.js
firstkfib(100)
and then the program hangs
I don't know if you are familiar with Time complexity and algorithmic analysis, but, it turns out that your program has an exponential running time. This basically means that, as the input increases, the time it takes to run your program increases exponentially. (If my explanation is not very clear, check this link)
It turns out that this sort of running time is extremely slow. For example, if it takes 1 ms to run your program for k=1, it would take 2^100 ms to run it for k=100. This turns out to be a ridiculously big number.
In any case, as Zhehao points out, the solution is to save the value of fib(n-1) and fib(n-2) (in an array, for example), and reuse it to compute fib(n). Check out this video lecture from MIT (the first 15 mins) on how to do it.
You may want to try printing out the numbers as they are being computed, instead of printing out the entire list at the end. It's possible that the computation is hanging somewhere along the line.
On another note, this is probably the most inefficient way of computing a list of fibonacci numbers. You compute fibonacci(n) and then fibonacci(n+1) without reusing any of the work from the previous computation. You may want to go back and rethink your method. There's a much faster and simpler iterative method.
writing intense computational code in nodeJS leads to blocking. since Fibonacci is an intense computational code so might end up blocking.
I was messing around with the benchmark site jfprefs and created my own benchmark at http://jsperf.com/prefix-or-postfix-increment/9.
The benchmarks are variations of Javascript for loops, using prefix and postfix incrementors and the Crockford jslint style of not using an in place incrementor.
for (var index = 0, len = data.length; index < len; ++index) {
data[index] = data[index] * 2;
}
for (var index = 0, len = data.length; index < len; index++) {
data[index] = data[index] * 2;
}
for (var index = 0, len = data.length; index < len; index += 1) {
data[index] = data[index] * 2;
}
After getting the numbers from a couple of runs of the benchmark, I noticed that Firefox is doing about 15 operations per second on average and Chrome is doing around 300.
I thought JaegerMonkey and v8 were fairly comparable in terms of speed? Are my benchmarks flawed somehow, is Firefox doing some kind of throttling here or is the gap really that large between the performance of the Javascript interpreters?
UPDATE: Thanks to jfriend00, I've concluded the difference in performance is not entirely due to the loop iteration, as seen in this version of the test case. As you can see Firefox is slower, but not as much of a gap as we see in the initial test case.
So why is the statement,
data[index] = data[index] * 2;
So much slower on Firefox?
Arrays are tricky in JavaScript. The way you create them, how you fill them (and with what values) can all affect their performance.
There are two basic implementations that engines use. The simplest, most obvious one is a contiguous block of memory (just like a C array, with some metadata, like the length). It's the fastest way, and ideally the implementation you want in most cases.
The problem is, arrays in JavaScript can grow very large just by assigning to an arbitrary index, leaving "holes". For example, if you have a small array:
var array = [1,2,3];
and you assign a value to a large index:
array[1000000] = 4;
you'll end up with an array like this:
[1, 2, 3, undefined, undefined, undefined, ..., undefined, 4]
To save memory, most runtimes will convert array into a "sparse" array. Basically, a hash table, just like regular JS objects. Once that happens, reading or writing to an index goes from simple pointer arithmetic to a much more complicated algorithm, possibly with dynamic memory allocation.
Of course, different runtimes use different heuristics to decide when to convert from one implementation to another, so in some cases, optimizing for Chrome, for example, can hurt performance in Firefox.
In your case, my best guess is that filling the array backwards is causing Firefox to use a sparse array, making it slower.
I hate to give you such a simple answer, but pretty simply: instruction branching: http://igoro.com/archive/fast-and-slow-if-statements-branch-prediction-in-modern-processors/
From what I get from the benchmark, there's something under the hood in these engines that is giving the instruction prediction features of the processor hell.