Complexity of nested for loops starting from the last iteration - javascript

function solution(A) {
var len = A.length;
cnt = 0;
for(i = 0; i < len - 1; i++){
for (a = i + 1; a < len; a++){
if (A[i] == A[a]){cnt++;}
else{continue;}
}
if(cnt > 1000000000){return 1000000000;}
}
return cnt;
}
So this is a code for counting identical pairs of an array, I know that 2 for loops give time complexity of O(n2). Is it always the case? Even if the next iteration goes through only remaining part of the array?

Yes this will be roughly O(1/2n^2) but since constants aren't really that important this will end up being O(n^2)

Related

Why is this highly iterative code faster than less iteration using a dictionary (js obbject really...)

This question is specific to the hacker rank problem Largest Permutation
I wrote a solution in javascript that works for most cases (A), but there are some select test cases where it times out. Ok... so then it must not be very efficient. I found someone else's solution to the problem (B) which is highly iterative. This loops through the given array at least once total, and then through the rest of the array at least K times. This seems very inefficient to me but this approach did not cause a timeout and I can't figure out why that is... one of these seems to be A: O(n) vs B: O(n^2) in my analysis but I guess im wrong... so I am asking here to see if anyone can help me figure out why this is or what the correct algorithm speed analysis is
These code snippets are the function body of a function that takes arr as an argument
A) My solution
const indices = {}
arr.forEach((n,i) => {
indices[n] = i
})
let count = 0
while(count < k){
// swap to earliest index (count)
const targetValue = arr.length - count
const targetIndex = indices[targetValue]
let tmp = arr[count]
arr[count] = arr[targetIndex]
arr[targetIndex] = tmp
//update indices
indices[targetValue] = count
indices[tmp] = targetIndex
count++
}
return arr
B) an alternative that to me should be slower but seems to be faster...
let n = arr.length
for(var i = 0; i < n - 1; i++) {
if( k > 0) {
var max = i;
for(var j = i + 1; j < n; j++){
if(arr[j] > arr[max])
max = j;
}
if(max != i) {
var temp = arr[max];
arr[max] = arr[i];
arr[i] = temp;
k--;
}
}
}
return arr
There are these issues with your implementation:
When k is larger than arr.length, then the arr.length - count will become 0 or less and thus targetValue will be a value that is not in the array. And so targetIndex will be undefined.
Your loop represents O(𝑘), and as 𝑘 can be much larger than 𝑛, this can make a huge difference in running time.
When the swap is a none-operation because the value happens to already be in its optimal position, then count is still incremented, reducing the number of actual swaps that are done.
Not an issue, but a for loop seems more appropriate here than a while.
Here is a correction of your main loop:
for (let count = 0; count < k && count < arr.length; count++) {
const targetValue = arr.length - count
if (arr[count] != targetValue) { // target not at optimal index?
// swap to earliest index (count)
const targetIndex = indices[targetValue]
let tmp = arr[count]
arr[count] = arr[targetIndex]
arr[targetIndex] = tmp
//update indices
indices[targetValue] = count
indices[tmp] = targetIndex
}
else k++; // Allow one more swap, as this was a no-op
}

++i vs i++ in javascript confusing function

What would be the difference between
var nums = [];
for (var i = 0; i < 10; ++i) {
nums[i] = i+1;
}
and
var nums = [];
for (var i = 0; i < 10; i++) {
nums[i] = i+1;
}
In the for loop, i = 0, but in the first iteration, would nums[i] = nums [0] or nums [1] since we are using ++i? How would the first iteration be different if i++ were used instead?
Update: For this particular for loop it doesn't matter. However, I'm interested to see a for loop where ++i vs i++ matters.
They would be exactly the same; ++i and i++ have the same effect on i, but the value of each expression is different; in this context, since the value is ignored, the code behaves the same.
As an example where switching between the two would matter, here is some truly awful code:
for ( var i=0; i++ < 10; )
++i increments before the "return", i++ increments after
var i = 0;
i++; //=> 0
i; //=> 1
var j = 0;
++j; //=> 1
j; //=> 1
For the purposes of your for loop, it doesn't make a difference.
In for loops, there is no difference. The difference between ++i and i++ is the value returned by the expression, but the expression is evaluated after each pass of the loop and you ignore the value.
There is no difference between the two. The incremented value will be ignoreed as it will happen at the end of the loop.
EDIT:
It makes no difference in the for loop if you write
for (var i = 0; i < 10; ++i) {
or
for (var i = 0; i < 10; i++) {
You will get the same results in both the cases. The reason why most of the people use i++ or better to say why i++ is more popular over ++i in a for loop is probably because people come from a habit of using i++ which was majorly used in C. Also to note that in C++ you can write your own version of ++ operator.
They are the same. The increment occurs at the end of the body of the loop.
i.e. you can view the loop as
var i = 0;
while (i < 10) {
... Body of loop
i++ or ++i;
}

Counting Sort array values aren't changing

I am trying to implement the counting sort algorithm. Based on the pseudocode from Introduction to Algorithms (and if you don't know it it's just a book), I came up with this code:
var countingSort = function(array, array2, k){
var a = [];
a.length = k;
for(var i in a){
a[i] = 0;
}
for(var j in array){
a[array[j]] += 1;
}
for(var i in a){
a[i] += a[i - 1];
}
for(var j = array.length; j >= 0; j--){
array2[a[array[j]]] = array[j];
a[array[j]] -= 1;
}
};
When I use the function, however, my array stays the same (I put in all the arguments!) How to fix this? Can someone please explain what is going on?
First of all, you shouldn't use a for in loop in short because it doesn't only iterate over the elements in the array but also over all the properties on the of Array object. Here's more info
In you case, a simple for loop would suffice.
Further, you should use descriptive names so that you (now or when you are looking at the code later on) or somebody else can understand the code more clearly.
I assume the variables in your program mean the following:
array stores the initial data to be sorted.
array2 stores the final, sorted list.
k is the max value in the array (all values are in the range 0..k)
a is the array used to count unique occurrences of values in array
These can be renamed into something like:
This one is fine as array
array2 can be renamed to sorted
k can be renamed to max
a can be renamed to count
Another thing you are doing wrong is in the last for loop. You are starting the loop at array.length but arrays are 0-indexed in javascript so your first value is out-of-bounds. You should start from array.length - 1.
And as far as setting a.length = k, this is not necessary in javascript because arrays are objects and objects have no direct concept of length. You can view arrays in javascript as dynamic lists.
Adding all the stated changes, here is how your code could look like:
function countingSort(array, sorted, max){
var i, j;
var count = [];
// initialize counting array
for(i = 0; i <= max; i++){
count[i] = 0;
}
// count unique occurrences
for(i = 0; i <= max; i++){
count[array[i]] += 1;
}
// compute proper indices
for(i = 1; i <= max; i++){
count[i] += count[i - 1];
}
// sort
for(i = array.length - 1; i >= 0; i--){
sorted[count[array[i]] - 1] = array[i];
count[array[i]] -= 1;
}
}
Running example:
var countingSort = function(array, sorted, max) {
var i, j;
var count = [];
// initialize counting array
for (i = 0; i <= max; i++) {
count[i] = 0;
}
// count unique occurrences
for (i = 0; i <= max; i++) {
count[array[i]] += 1;
}
// compute proper indices
for (i = 1; i <= max; i++) {
count[i] += count[i - 1];
}
// sort
for (i = array.length - 1; i >= 0; i--) {
sorted[count[array[i]] - 1] = array[i];
count[array[i]] -= 1;
}
}
document.getElementById("button").onclick = function() {
var i, array, max, sorted = [];
array = document.getElementById("input").value.split(',');
// convert strings to numbers
for (i = 0; i < array.length; i++) {
array[i] = +array[i];
}
// find max
var max = Number.MIN_VALUE;
for (i = 0; i < array.length; i++) {
if (max < array[i]) {
max = array[i];
}
}
countingSort(array, sorted, max);
document.getElementById("result").value = sorted;
}
input {
width: 100%;
margin: 10px 0;
padding: 10px;
border: 1px solid #018bbc;
border-radius: 5px;
}
<input type="text" id="input" placeholder="Enter comma separated list of integers">
<button type="button" id="button">Sort</button>
<input type="text" id="result" disabled placeholder="Sorted array is displayed here...">
Additionally, here is a version of counting sort which IMHO seems more intuitive and less complicated than the general approach above:
var countingSort = function(array, sorted, max) {
var i, j, count = [];
// initialize counting array
for (i = 0; i <= max; i++) {
count[i] = 0;
}
// count unique occurences
for (i = 0; i < array.length; i++) {
count[array[i]] ++;
}
// sort
for (i = 0, j = 0; i <= max; i++) {
while (count[i] > 0) {
sorted[j++] = i;
count[i] --;
}
}
};

Remove element in nested loop

I am writting a simple metaballs implementation in JS. I have an array of the metaballs and i iterate through all of them every frame, and for each one I check the distance to every other metaball and if they are close enough I need to merge them.
This is how I guess it could look, but I don't know how to properly remove the element from array and not break the loops.
for(var i = 0; i < points.length; i++) {
for(var j = 0; j < points.length ; j++) {
if(i != j) {
if(distance < 10) {
//remove one of the points using splice
}
}
}
}
Thanks for help.
First, start your inner loop at i + 1. You've already compared elements up to i, so there's no need to repeat, right? That let's you get rid of your if statement as well.
Then, when you splice, decrement j so as to not skip the next element.
for(var i = 0; i < points.length; i++) {
for(var j = i + 1; j < points.length ; j++) {
if (distance(i, j) < 10) {
points.splice(j--, 1);
}
}
}

Why this loop backwards is much slower than going forward?

I have a answer to another guy question here How to count string occurrence in string?
So I was playing with algorithms here, and after benchmarking some functions I was wondering why a backwards loop was significantly slower than forward.
Benchmark test here
NOTE: This code below does not work as supposed to be, there are
others that work (thats not the point of this question), be aware
before Copying>Pasting it
Forward
function occurrences(string, substring) {
var n = 0;
var c = 0;
var l = substring.length;
for (var i = 0, len = string.length; i < len; i++) {
if (string.charAt(i) == substring.charAt(c)) {
c++;
} else {
c = 0;
}
if (c == l) {
c = 0;
n++;
}
}
return n;
}
Backwards
function occurrences(string, substring) {
var n = 0;
var l = substring.length - 1;
var c = l;
for (i = string.length; i > 1; i--) {
if (string.charAt(i) == substring.charAt(c)) {
c--;
} else {
c = l;
}
if (c < 0) {
c = l;
n++;
}
}
return n;
}
I think the backwards test has a bug:
for (i = string.length; i > 1; i--) {
should be
for (i = string.length - 1; i >= 0; i--) {
When i is string.length, string.charAt(i) is undefined. Do this several thousand times, and it could yield a substantial difference.
Here's a modified test that seems to yield much closer to identical performances.
I found the bottle-neck myself.
when I did this
for (i = string.length; i > 1; i--) {
I accidentaly deleted the "var" from var i, so I've made i global.
After fixing it I got the expected results.
for (var i = string.length; i > 1; i--) {
I never though that this may be a HUGE difference, so pay attention guys.
Fixed Benckmark test here
Before:
After:
PS: for practical use, do NOT use this functions, the indexOf version is much faster.
What data are you testing with. If your data has lots of matching prefixes but not many false matches the other way round , that might affect it.
also wont that search bug on cases like "aaabbaaa" try to find "aab" it will match aa, then fail , then continue from third a and fail. ?
Because they are not complete mirrored functions, add console.log()s inside all ifs and elses of both functions and compare the results, you will see that the tests aren't fair.
You did something wrong. I suggest to ensure that they both work as expected before even start the testings.

Categories