Difference between these two for loops - javascript

for (var ctr = arr.length - 1; ctr >= 0; ctr--) {
}
for (var ctr = 0; ctr < arr.length; ctr++) {
}
Does both of them does the same job or the first one does things
differently.
Which is the best way to perform compared to the above
two.

First one will start from bottom of array and will reach top. Second one will start from top to bottom of array.
If your array has { 3, 2, 1 } and you print this in first loop, it will print 1, 2, 3 and in second loop it will print 3, 2, 1.
Found this http://oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html which tells about improving performance of javascript. According to it
Another simple way to improve the performance of a loop is to decrement the iterator toward 0 rather than incrementing toward the total length. Making this simple change can result in savings of up to 50% off the original execution time, depending on the complexity of each iteration.
So first one will give better performance.
Hope this helps you.

The first one loops through the array in reverse. The second one in the order the elements appear.

The two loops are different in the direction of an array traversal:
starts from the last element and finishes in the first element
vice versa, starts from the fist element and finishes in the last one
Which is the best, depends on your needs.
Consider, for example, the task of finding the first/last occurrence of a character in an array.

They both iterate over the contents of an array, but they do it in opposite directions. The first starts from the last element of the array, and works backwards to the first element; the second starts from the first element, and works forwards to the last.
In most cases, they'll provide the same results. However, it's a common practice when you're going to be removing elements from an array to iterate backwards (the first code sample), as any changes to the indices after removing an element will only affect the elements that have already been examined.

The first loops backwards. The second loops forwards.
The first will have better performance (because the second has to access the arr.length each time it goes around the loop), but not significantly so unless you are dealing with a lot of objects or looping over them many times.
You can get a similar performance boost with:
for (var i = 0, j = arr.length; i < j; i++) {
}

Related

What is the time complexity of this recursive solution for removing duplicates?

After I complete a Leetcode question, I always try to also determine the asymptotic time complexity, for practice.
I am now looking at problem 26. Remove Duplicates from Sorted Array:
Given a sorted array nums, remove the duplicates in-place such that
each element appears only once and returns the new length.
Do not allocate extra space for another array, you must do this by
modifying the input array in-place with O(1) extra memory.
Clarification:
Confused why the returned value is an integer but your answer is an
array?
Note that the input array is passed in by reference, which means a
modification to the input array will be known to the caller as well.
Internally you can think of this:
// nums is passed in by reference. (i.e., without making a copy) int
len = removeDuplicates(nums);
// any modification to nums in your function would be known by the caller.
// using the length returned by your function, it prints the first len elements.
for (int i = 0; i < len; i++) {
print(nums[i]);
}
Example 1:
Input: nums = [1,1,2]
Output: 2, nums = [1,2]
Explanation: Your
function should return length = 2, with the first two elements of nums
being 1 and 2 respectively. It doesn't matter what you leave beyond
the returned length.
My code:
/**
* #param {number[]} nums
* #return {number}
*/
var removeDuplicates = function(nums) {
nums.forEach((num,i) => {
if(nums[i+1] !== null && nums[i+1] == nums[i] ){
nums.splice(i, 1);
console.log(nums)
removeDuplicates(nums)
}
})
return nums.length;
};
For this problem, I got O(log n) from my research. Execution time halves each time it runs. Can someone please verify or determine if I am wrong?
Are all recursive functions inherently O(logn)? Even if there are multiple loops?
For this problem, I got O(log n) from my research. Execution time halves for each time it's run. Can someone please verify or determine if I am wrong?
The execution time does not halve for each run: imagine an extreme case where the input has 100 values and they are all the same. Then at each level of the recursion tree one of those duplicates will be found and removed. Then a deeper recursive call is made. So for every duplicate value there is a level in the recursion tree. So in this extreme case, the recursion tree will have a depth of 99.
Even if you would revise the algorithm, it would not be possible to make it O(log n), as all values in the array need to be read at least once, and that alone already gives it a time complexity of O(n).
Your implementation uses splice which needs to shift all the values that follow the deletion point, so one splice is already O(n), making your algorithm O(n²) (worst case).
Because of the recursion, it also uses O(n) extra space in the worst case (for the call stack).
Are all recursive functions inherently O(logn)?
No. Using recursion does not say anything about the overall time complexity. It could be anything. You typically get O(logn) when you can ignore O(n) (like half) of the current array when making the recursive call. This is for instance the case with a Binary Search algorithm.
Improvement
You can avoid the extra space by not using recursion, but an iterative method. Also, you are not required to actually change the length of the given array, only to return what its new length should be. So you can avoid using splice. Instead, use two indexes in the array: one that runs to the next character that is different, and another, a slower one, to which you copy that new character. When the faster index reaches the end of the input, the slower one indicates the size of the part that has the unique values.
Here is how that looks:
var removeDuplicates = function(nums) {
if (nums.length == 0) return 0;
let len = 1;
for (let j = 1; j < nums.length; j++) {
if (nums[j-1] !== nums[j]) nums[len++] = nums[j];
}
return len;
};

Confused on reversing an array

I want to reverse an array that I input into a function.
But for some reason the console returns the first value of the array instead of taking the full array within the while loop so it can unshift the value at the end to the front then delete that same value.
function littleWHEW(lemonade) {
let i = lemonade.length - 1;
while (i >= 0) {
lemonade.unshift(lemonade[i])
lemonade.pop(lemonade[i])
i = i - 1
}
return lemonade
}
console.info(littleWHEW([1,2,3,4,5]))
Just use the
reverse()
method:
function littleWHEW(lemonade) {
return lemonade.reverse();
}
You should not add a parameter to the pop() method, by the way.
Since you asked for explanation, let's take a deep investigation. Before we do, please take a look at
unshift and pop
Firstly i = 4. Here're what happens in one loop:
[1,2,3,4,5] is the original array. lemonade.unshift(lemonade[i]) adds one element to the first position of lemonade. At this point i = 4 so lemonade[4] = 5, we have [5,1,2,3,4,5] (notice the bold).
Now you pop the last one out. [5,1,2,3,4,5] becomes [5,1,2,3,4].
You decrease i.
Now i = 3, And here're what happens in second loop:
[5,1,2,3,4] is the original array. lemonade.unshift(lemonade[i]) adds one element to the first position of lemonade. At this point i = 3 so lemonade[3] = 3, we have [3,5,1,2,3,4] (notice the bold).
Now you pop the last one out. [3,5,1,2,3,4] becomes [3,5,1,2,3].
You decrease i.
After one loop, your i does not point to the last element as expected, and makes things wrong (as second loop does).

Javascript array splice causing out of memory exception?

I am basically trying to sort an input of numbers on the fly by inserting the numbers to the correct position (not 100% sure but this should be insertion sort). My understanding is that to insert into an array in javascript you need to use the array splice method http://www.w3schools.com/jsref/jsref_splice.asp .
My code in attempt of achieving my goal is as below:
var N = parseInt(readline());
var powers = [0];
for (var i = 0; i < N; i++) {
var pi = parseInt(readline());
for(var j=i;j<powers.length; j++ ){
if(powers[j]>pi){
powers.splice(j,0,pi);
}
else if(j+1==powers.length){
powers[j+1]=pi;
}
}
}
When I run this code I get an out of memory exception. I just want to understand is what I am doing wrong in the code above. If I am using the splice method wrong and it is the cause of the memory leak, what is actually happening under the hood?
I know there are other ways I could do this sorting but I am particularly interested in doing an insertion sort with javascript arrays.
In your else condition, you're adding to the array, making it one longer. That means when the loop next checks powers.length, it will be a higher number, which means you'll go into the loop body again, which means you'll add to the array again, which means you'll go back into the loop body again, which means...you see where this is going. :-)
Once you've added the number to the array (regardless of which branch), exit the loop (for instance, with break).
Side note: You won't be doing a proper insertion sort if you start j at i as you are currently. i is just counting how many entries the user said they were going to enter, it's not part of the sort. Consider: What if I enter 8 and then 4? If you start j at i, you'll skip over 8 and put 4 in the wrong place. j needs to start at 0.

Looping over undefined array keys

Problem:
I have a DB containing math exercises, split by difficulty levels and date taken.
i want to generate a diagram of the performance over time.
to achieve this, i loop through the query results, and ++ a counter for the level and day the exercise was taken.
example: level 2 exercise was taken at 01.11.2015.
this.levels[2].daysAgo[1].amountTaken++;
with this, i can build a diagram, where day 0 is always today, and the performance over days is shown.
now levels[] has a predefined amount of levels, so there is no problem with that.
but daysAgo[] is very dynamic (it even changes daily with the same data), so if there was only one exercise taken, it would wander on a daily basis (from daysAgo[0] to daysAgo[1] and so on).
the daysAgo[] between that would be empty (because there are no entries).
but for evaluating the diagram, i need them to have an initialized state with amountTaken: 0, and so on.
problem being: i can't know when the oldest exercise was.
Idea 1:
First gather all entries in a kind of proxy object, where i have a var maxDaysAgo that holds the value for the oldest exercise, then initialize an array daysAgo[maxDaysAgo] that gets filled with 0-entries, before inserting the actual entries.
that seems very clumsy and overly complicated
Idea 2:
Just add the entries this.level[level].daysAgo[daysAgo].amountTaken++;, possibly leaving the daysAgo array with a lot of undefined keys.
Then, after all entries are added, i would loop over the daysAgokeys with
for (var i = 1; i < this.maxLevel; i++) { // for every level
for (var j = 0; j < this.levels[i].daysAgo.length; j++) {
but daysAgo.lengthwill not count undefined fields, will it?
So if i have one single entry at [24], length will still be 1 :/
Question:
How can I find out the highest key in an array and loop until there, when there are undefined keys between?
How can i adress all undefined keys up until the highest (and not any more)?
Or: what would be a different, more elegant way to solve this whole problem altogether?
Thanks :)
array.length returns one higher than the highest numerical index, so can be used to loop though even undefined values
as a test:
var a=[]
a[24]=1
console.log(a.length)
outputs 25 for me (in chrome and firefox).

When should I use forEach?

I can either do,
var arr = [];
arr.forEach(function(i) {
i;
});
for (var i = 0, length = arr.length; i < length; ++i) {
arr[i];
}
When should I use one over the other, is there performance differences?
You use foreach whenever :
your array is associtive or has gaps, i.e. you cannot reach every element by an incremented number (1,2,5, 'x', -7)
you need to iterate in exactly the same order as they appear in the array. (e.g. 2,1,3)
you want to be sure not the get into an endless loop
The last point is the main difference: foreach works on a copy, so even if you alter the elements, the array remains intact and can be iterated without defects.
That copy makes foreach somewhat slower than for, since it has to copy data. Keep in mind that some old or rare browsers don´t supports foreach, but they do support "for". Unless your array is really big (10.000 + items), ignore the speed difference. It´s in the milliseconds.
You use for whenever
you want an easy way to aler the array you are moving on
you want specific sequences, e.g. for ($i=100; $i < 1000; $i += 5) resulting in 100, 105, 110...

Categories

Resources