Time complexity for a loop with two nested loops? - javascript

I understand that
var arr; // This is an array of arrays
for (i = 0; i < arr.length; i++)
{
for(j = 0; j < arr[i].length; j++)
{
// Some code
}
}
is n^2, however my code below is a double nested for loop and im just curious on what the complexity for this type of function would look like
var arr; // This is an array of arrays
for (i = 0; i < arr.length; i++)
{
for(j = 0; j < arr[i].length; j++)
{
// Some code
}
for(k = 0; k < arr[i].length; k++)
{
// Some code
}
}

The complexity of consecutive pieces of code is the maximum complexity of each of them. So if you have two consecutive loops, and they're both O(n), then the complexity of both together is also O(n).
Since these two loops are nested inside an O(n) loop, the complexity of the whole thing is O(n^2). Just like the complexity of the original code.

A loop has the complexity O(n * content), a block of statement has the complexity of all its members added up O(n1 + n2 + ...). Now in your case that is
// v outer loop
// v inner loop 1
// v inner loop 2
O(n * ((n * 1) + (n * 1)))
= O(n * (n + n))
= O(n * 2n) // constants can be ignored
= O(n * n)
= O(n²)

Related

What is the time complexity of these 3 loops?

What is the time complexity of this code?
let time = 0;
for(let i = 1; i <= n; i++)
{
for(let j = 1; j <= i; j++)
{
for(let k = 1; k <= n*n; k += i*i)
{
time++
}
}
}
Is the innermost loop O(1) or O(n^2)?
The answer is O(N^2logN).
Analysis:
For a constant i, the innermost loop will be executed for about (N*N)/(i*i) times. The second loop will be executed for i times. So time++ will be executed for about ((N*N)/(i*i))*i = (N*N)/i times.
So the total expense will be the sum for every i.
(N*N)*(1/1+1/2+1/3....1/N) ≈ N^2logN is your answer.

My browser lags when I try a loop function?

I wrote a simple nested loop function to multiply all items in an array and output the total value, but each time is I run a loop function my browser either crashes or doesn't stop loading
function multiplyAll(arr){
Let product = 1;
for(let i = 0; i <
arr.length; i++){
for(let j = 0; j <
arr[i].length; j *= product);
}
return product;
}
multiplyAll([[1], [2], [3]]);
You are creating an infinite loop here because of
for (let j = 0; j < arr[i].length; j *= product);
Here, j is always 0.
If you want to multiply all the nested value then you should do as:
function multiplyAll(arr) {
let product = 1;
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; ++j)
product *= arr[i][j];
}
return product;
}
console.log(multiplyAll([[1], [2], [3]]));
If you just want to multiple all the nested value then you can simply do as:
function multiplyAll(arr) {
return arr.flat().reduce((acc, curr) => acc * curr, 1);
// If you want to get numbers at any depth then you can flat at any level
// using Infinity as
// return arr.flat(Infinity).reduce((acc, curr) => acc * curr, 1);
}
console.log(multiplyAll([[1], [2], [3]]));
Well, it looks like you have multiple issues, two of them are already as following:
In line 2 you wrote once Let with a big letter at the beginning.
Your second array needs an {} otherwise it will error out
Can you please explain to me j*= product? Can you maybe include a few examples of how you would call this Code and what kind of response you would get? depending on that I will create you a Clear answer!

Fastest way to find duplicates between two arrays javascript

There are a lot of posts on the easiest way to find duplicates in two arrays, but what is absolute fastest way? Is there a way to avoid using two for loops and get the function from O(n^2) time to O(n) time? The arrays I have contain ~1000 items each. Before running the function I check which array is longer and use that array as the toCheckAgainst variable.
var containingBoth = [];
function checkArrays(toCheck, toCheckAgainst){
for(var i=0;i<toCheck.length;i+=1){
for(var j=0;j<toCheckAgainst.length;j+=1){
if (toCheck[i] === toCheckAgainst[j]) {
containingBoth.push(toCheck[i]);
}
}
}
}
This can be the another way to achieve this.Your current solution have the looping on both of the arrays and looping on the longest one which slower down the process in large arrays e.g if one longest array has 1000 vals and shorter array has only 2 in that case you are looping 1000 values to find out the dupes which can not be more than 2 in that case.
Below solution loop is only on the array which is shorter than the other array because we are only interested in dupes and even if both arrays are of same length below solution is faster because in your solution you are looping on both arrays whereas below code just loop on one.
Did some testing on comparing difference in speed in Niles code and mine see the results here Niles Code and my code and its approximately 50% faster with the arrays of 1000 values each
var arr1 = ["Test1", "test2", "test3","test5","test6","test4"];
var arr2 = ["test1", "test4","test5","test6","test2","Test1"];
var result = [];
(arr1.length>arr2.length?arr2:arr1).forEach(function(key) {
if (-1 != (arr1.length>arr2.length?arr1:arr2).indexOf(key) && -1 == result.indexOf(key))
result.push(key);
}, this);
alert(result); //duplicate values arr
Edited to add example code
You can do it in O(n) if both arrays--with lengths "k" and "l" respectively--are already sorted. You can do it by merging the two arrays (not in memory, of course, just algorithmically) like in merge-sort with k+l comparisons.
If both arrays are not sorted at all you can do it in O(n log n) (e.g. with the merge-sort mentioned above) with O(n²) comparisons and because you can do your task with brute force in O(n²) already, sorting the arrays would be redundant here.
But not all sets are completely unsorted, especially if they are big. If we take quicksort as an example you can expect O(n log n) on average with O(n log n) comparisons. But be aware that the worst case of quicksort is O(n²) when the set is already sorted!
A very simple way if your arrays are sorted and contain no duplicates:
Take the individual entries of the smaller array and do a binary search for them in the larger array -> O(n log n) (binary search is O(log n) and you do it n times). The smaller array does not even have to be sorted if it is guaranteed that it contains no duplicates.
Summary: you can do it faster than O(n²). It depends on the input how fast "faster" actually gets but you can get it down to O(n) (plus a small constant) in the best case and O(n log n) on average.
'use strict'
var primesieve;
var buffer;
var primelimit;
function clear(where) {
primesieve[where >>> 5] &= ~((1 << (31 - (where & 31))));
}
function get(where) {
return ((primesieve[where >>> 5] >>> ((31 - (where & 31)))) &
1);
}
function nextset(from) {
while (from < primelimit && !get(from)) {
from++;
}
if (from === primelimit && !get(from)) {
return - 1;
}
return from;
}
function fillsieve(n) {
var k,
r,
j;
n = n + 1;
primelimit = n - 1;
k = Math.ceil(n / 32);
if (typeof ArrayBuffer !== 'function') {
buffer = new ArrayBuffer(k * 4);
} else {
buffer = k;
}
primesieve = new Uint32Array(buffer);
while (k--) {
primesieve[k] = 0xffffffff;
}
clear(0);
clear(1);
for (k = 4; k < n; k += 2) {
clear(k);
}
r = Math.floor(Math.sqrt(n));
k = 0;
while (k < n) {
k = nextset(k + 1);
if (k > r || k < 0) {
break;
}
for (j = k * k; j < n; j += 2 * k) {
clear(j);
}
}
}
function approx_limit(prime_pi) {
if (prime_pi < 10) {
return 30;
}
// see first term of expansion of li(x)-li(2)
return Math.ceil(prime_pi * (Math.log(prime_pi * Math.log(prime_pi))));
}
function primes(prime) {
var ret,
k,
count,
i;
ret = [];
k = 0;
i = 0;
count = prime;
while (count--) {
k = nextset(k + 1);
if (k > primelimit || k < 0) {
break;
}
ret[i++] = k;
}
return ret;
}
// very simple binary search
Array.prototype.bsearch = function(needle) {
var mid, lo = 0;
var hi = this.length - 1;
while (lo <= hi) {
mid = Math.floor((lo + hi) / 2);
if (this[mid] > needle) {
hi = mid - 1;
} else if (this[mid] < needle) {
lo = mid + 1;
} else {
return this[mid];
}
}
// assumes no entry "-1", of course
return -1;
};
var limit = 10 * 1000;
var a, b, b_sorted, u;
var a_length, b_length, u_length;
fillsieve(approx_limit(limit));
// the first array is filled with primes, sorted and unique
a = primes(limit);
// the second array gets filled with an unsorted amount of
// integers between the limits 0 (zero) and "limit".
b = [];
for(var i = 0;i < limit;i++){
b[i] = Math.floor( Math.random() * (limit + 1));
}
a_length = a.length;
b_length = b.length;
console.log("Length of array a: " + a_length);
console.log("Length of array b: " + b_length);
var start, stop;
u = [];
// Brute-force
start = performance.now();
for(var i = 0; i < a_length; i++){
for(var j = 0; j< b_length; j++){
if(a[i] == b[j] && a[i] != u[u.length - 1]){
u.push(a[i]);
}
}
}
stop = performance.now();
console.log("Brute force = " + (stop - start));
console.log("u-length = " + u.length);
console.log(u.join(","));
u = [];
b_sorted = [];
// work on copy
for(var i = 0; i < b_length; i++) b_sorted[i] = b[i];
var entry;
// Sort the unsorted array first, than do a binary search
start = performance.now();
// ECMA-script's arrays sort() function sorts lexically
b_sorted.sort(function(a,b){return a - b;});
for(var i = 0; i < a_length; i++){
entry = b_sorted.bsearch(a[i])
if( entry != -1 && entry != u[u.length - 1]){
u.push(entry);
}
}
stop = performance.now();
console.log("Binary search = " + (stop - start));
console.log("u-length = " + u.length);
console.log(u.join(","));
This runs on my little AMD A8-6600K in around 56 seconds with the brute force algorithm and in about 40 milliseconds (yes, milliseconds!) with the binary search and that number even includes the sorting of the array.

finding an array in another Multidimensional array in javascript

I'm writing a simple snakes game using JavaScript and HTML5 canvas.
I have a Multidimensional array that hold snake block like this:
snake=[[1,1],[1,2]];
and set it on arrayMap using (snake.indexOf([i],[j])!=-1) then draw arrayMap on canvas.
for (var i = 0; i < blocksHeightCount; i++) {
for (var j = 0; j < blocksWidthCount; j++) {
if ((snake.indexOf(i,j)!=-1)||
(walls.indexOf(i,j)!=-1)||
(foods.indexOf(i,j)!=-1)) {
arrayMap[i][j]=1;
} else {
arrayMap[i][j]=0;
}
}
}
for (var i = 0; i < blocksHeightCount; i++) {
for (var j = 0; j < blocksWidthCount; j++) {
Block = arrayMap[i][j];
if (Block!=0){
ctx.fillStyle = (Block != 9) ? colors[Block]
: "#bdc3c7";
ctx.fillRect(j * cubeWidth, i * cubeHeight
, cubeWidth-.4,cubeHeight-.4);
}
}
}
the problem is indexOf isn't working when I set array on it!
It works fine when I set indexOf("i,j") but i need it to be array.
please help, thx
First solution : using Array.map
Each element of your arrays snake, walls and foods is an array with 2 elements. So to check if an [x,y] exists in one of the arrays you need a simple way to
compare two arrays [x1, y1] and [x2, y2]. Comparing arrays directly using the operator == will compare their references and not values (Thanks #Elena for the remarque). A way to compare values
would be to affect a hash to each array and compare hashes. By hash I mean a number which is unique for each array of type [x, y]. That could be x * blocksWidthCount + y
in your case and the code will be :
function getHash(x, y){
return x * blocksWidthCount + y;
}
var blockHashes = snake.concat(walls).concat(foods).map(function(cell) {
return getHash(cell[0], cell[1]);
}); // hashes of all blocks in one array
for (var i = 0; i < blocksHeightCount; i++) {
for (var j = 0; j < blocksWidthCount; j++) {
if (blockHashes.indexOf(getHash(i, j)) != -1) {
arrayMap[i][j]=1;
} else {
arrayMap[i][j]=0;
}
}
}
Second Solution Changing the way we see things
Instead of looping over all cells and verifying if every single cell is a block which gives a complexity of O(N * M) (N number of cells and M number of blocks).
We can do better simply by supposing that there is no block and then loop over blocks and mark them as blocks which is in O(N + M) !
function markBlock(cell){
arrayMap[cell[0]][cell[1]] = 1;
}
for (var i = 0; i < blocksHeightCount; i++)
for (var j = 0; j < blocksWidthCount; j++)
arrayMap[i][j] = 0;
snake.forEach(markBlock);
walls.forEach(markBlock);
foods.forEach(markBlock);

Radix Sort in JavaScript

I've come up with the following but it predictably doesn't work.
var t = new Array(a.length);
var r = 4;
var b = 64;
var count = new Array(1<<r);
var pref = new Array(1<<r);
var groups = Math.ceil(b / r);
var mask = (1 << r) - 1;
var shift = 0;
for(var c = 0; c < groups; c++)
{
shift += r;
for(var j = 0; j < count.length; j++)
{
count[j] = 0;
}
for(var i = 0; i < a.length; i++)
{
count[ (a[i] >> shift) & mask ]++;
}
pref[0] = 0;
for(var i = 0; i < count.length; i++)
{
pref[i] = pref[i-1] + count[i-1];
}
for(var i = 0; i < a.length; i++)
{
t[ pref[ (a[i] >> shift) & mask ]++ ] = a[i];
}
for(var i = 0; i < a.length; i++)
{
a[i] = t[i];
}
// a is sorted?
}
This loop does basically the same thing, in a more Javascript-y way:
for (var div = 1, radix = 16; div < 65536 * 65536; div *= radix) {
var piles = [];
for (var i = 0; i < a.length; ++i) {
var p = Math.floor(a[i] / div) % radix;
(piles[p] || (piles[p] = [])).push(a[i]);
}
for (var i = 0, ai = 0; i < piles.length; ++i) {
if (!piles[i]) continue;
for (var pi = 0; pi < piles[i].length; ++pi)
a[ai++] = piles[i][pi];
}
}
Instead of doing it like a C programmer might, this loop builds a list of lists, one list for each possible 4-bit value. I avoid bit-shift operators because this is Javascript and while they do work, things get funny when numbers get large.
Starting with the low 4 bits of each value in "a", the code copies that element of "a" to the end of one of the "piles", that being the one corresponding to the 4-bit value. It then gathers up the piles and rebuilds "a" starting from all of the values whose low 4 bits were 0, then 1, etc. (Clearly there'll be some gaps, so those are skipped.) At the end of each iteration of the overall loop, the divisor is multiplied by the radix, so that the next set of 4 bits will be examined.
Once the divisor has exhausted the available range of integers, it's done.
Note that this will only work for positive numbers. Doing this with negative numbers gets a little weird; it might be easier to strip out the negative numbers into a separate array, flip the sign, sort, then reverse. Sort the positive numbers, and then finally glue the reversed negative numbers (flipping the signs again) to the front of the sorted positive numbers.
this
for(var i = 0; i < count.length; i++)
{
pref[i] = pref[i-1] + count[i-1];
}
is a problem because on the first iteration, i is zero and so pref[ 0 - 1 ] is not going to work very well.
I don't have a reference for radix sorts handy to determine what you should actually be doing here.

Categories

Resources