Algorithm: Next Greater Element I (from leetcode) - javascript

can someone please tell me what I'm missing in solving this algorithm? One problem I have is that my first if statement inside the nested loop is not evaluating, but I don't know why it wouldn't evaluate.
Here is the description of the problem:
You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2.
The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number.
Example 1:
Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]
Explanation:
For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
For number 1 in the first array, the next greater number for it in the second array is 3.
For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
link to original description
And here is my code so far:
var nums1 = [4,1,2];
var nums2 = [1,3,4,2];
var nextGreaterElement = function(findNums, nums) {
var holder = [];
for (var i = 0; i < findNums.length; i++) {
//loop through the 2nd array starting at the index of the first loop's current item.
for (var j = nums.indexOf(findNums[i]); i < nums.length - j; i++) {
if (nums[j+1] > nums[j]) {
holder.push(nums[j+1]);
break;
}
if (nums[nums.length]) {
holder.push(-1);
}
}
}
return holder;
};
nextGreaterElement(nums1, nums2)
Thanks for any help.

Problem: Updating variant i, but not variant j in inner loop (j-loop)
Missing: Debugging Effort
Problem Description
Theoretically, your code design should compare each value in nums1 to related parts of nums2. So, it would turn to a outer for-loop to loop on nums1 and an inner for-loop to loop related parts of nums2 for each iteration of the outer for-loop.
In your code, variant i is the index pointer for findNums (i.e. nums1) while variant j is the index pointer for nums (i.e. nums2). Variant i is always updating in both inner for-loop and outer for-loop while variant j is set once for every iteration of outer for-loop. This contradict to what you are suppose to do.
Debugging (Your Missing Work)
Find a piece of paper and a pen. Sit down, dry run the program and keep recording related info (variant i, variant j, findNums[i], nums[j], ...), you could figure out why your code is not working.
Possible Solution
var nextGreaterElement = function(findNums, nums) {
var holder = [];
for (var i = 0; i < findNums.length; i++) {
var hasNextGreaterElement = false;
// try to serach for next greater element
for (var j = nums.indexOf(findNums[i])+1; j < nums.length; j++) {
// handle case for next greater element is found
if (nums[j] > findNums[i]) {
holder.push(nums[j]);
hasNextGreaterElement = true;
break;
}
}
// handle case for next greater element is not found
if (!hasNextGreaterElement) {
holder.push(-1);
}
}
return holder;
};
var findNums=[4,1,2];
var nums=[1,3,4,2];
console.log(nextGreaterElement(findNums, nums));

You need to sort the array you are looking in to make it easier to find the number. If the array get big you might want a search algorithm to find the index in the array faster. With the array that is going to be looked in sorted you can grab the next number as the number that is one larger and check to see if you are at the end of the array. If you don't do this check the function will error when you can't find the number or when there is no number larger. Finally your second if statement didn't make sense. So I am checking to make sure that we are at the end of the array before outputting the -1 in the array.
var nextGreaterElement = function(findNums, nums) {
var holder = [];
//Should sort the array to make sure you get the next largest number
nums = nums.sort();
for (var i = 0; i < findNums.length; i++) {
//loop through the 2nd array starting at the index of the first loop's current item.
//for (var j = nums.indexOf(findNums[i]); i < nums.length - j; i++) {
for(var j = 0; j < nums.length; j++){
//check for value in array and make sure the value is not at the end
if (findNums[i] == nums[j] && j != nums.length - 1) {
holder.push(nums[j+1]);
break;
}
//check for the last element in array if so output -1
if (j == nums.length - 1) {
holder.push(-1);
}
}
}
return holder;
};

Related

How to iterate over an array of numbers to find the first number that occurs 3 times in the array

I have the following code
let range = [1,2,3];
let multiples = [1,2,3,4,5,6,2,4,6,3,6];
I want to find the first number in the multiples array that occurs range.lenght times (3);
I want to start with multiples[0] check how many times it occurs in multiples, if it occurs 3 times I want to return multiples[0], if it is less than 3 times, I want to check how many times multiples[1] occurs in the multiples array. If multiples[1] occurs 3 times I want to return multiples[1], else I move on to check multiples[2], etc. until I find a number that occurs 3 times. In the code above I should return 6.
I've looked at
How to count the number of certain element in an array?
and
Idiomatically find the number of occurrences a given value has in an array
and
get closest number out of array
among other research but have not figured it out yet.
I tried to simplify the question as much as possible. But if more info is needed it relates to this challenge on freeCodeCamp. Where I am at with my code is
function smallestCommons(arr) {
let sortArr = arr.sort((a, b) => a - b);
console.log(sortArr);
let range = [];
for (let i = sortArr[0]; i <= sortArr[1]; i++) {
range.push(i);
}
console.log("range = " + range);
let maxNum = range.reduce( (a, b) => a * b);
console.log("maxNum = " + maxNum);
let multiples = [];
for (let i = 0; i < maxNum; i++) {
let j = 0;
do {
multiples.push(j + range[i]);
j += range[i];
} while (j < maxNum);
//j = 0;
}
for (let i = 0; i < multiples.length; i++) {
let numberToFind = multiples[i];
/*stuck here hence my question, maybe I shouldn't even start with a for loop*/
//tried reduce, forEach, filter, while loop, do while loop
}
console.log("multiples = " + multiples);
}
console.log(smallestCommons([1,3]));
The logs are
1,3
range = 1,2,3
maxNum = 6
multiples = 1,2,3,4,5,6,2,4,6,3,6,NaN,NaN,NaN
What you can do is, first split your string with , and then using below function loop for check.
function countLength(arr, checkNumber) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === checkNumber) {
count++;
}
}
return count;
}
countLength(list, NUMBER YOU WANT TO CHECK);
And if you want to check first number occur for 3 time then you need to make change in function and introduce .map or .filter in action to count number.
Example
const multiples = [1,2,3,4,5,6,2,4,6,3,6];
let occurance_arr=[];
const aCount = [...new Set(multiples)].map(x => {
if(multiples.filter(y=> y==x).length == 3) {
occurance_arr.push(x);
}
});
console.log(occurance_arr);
Above code will give you 6 in console, if you have multiple value then 0th element is the answer you are looking for which is first three time occurrence of item.
You can loop through your list keeping an object that maps each number to the number of times you've seen it. You can check the counts object as you loop, so if you see a number and the count is one less than your target, you can return it. If you make it through the loop without returning you didn't find what you're looking for — return something sensible :
let range = [1,2,3]
let multiples = [1,2,3,4,5,6,2,4,6,3,6]
function findFirstMult(arr, len){
let counts = {} // to keep track of how many times you've seen something
for (let n of arr){ // loop throught the array
if (!counts[n]) counts[n] = 0 // if it's then first time you've seen n, defined that key
if (counts[n] == len - 1) return n // found it
counts[n] +=1 // otherwise increase the count
}
return undefined
}
console.log(findFirstMult(multiples, range.length))
This will require only one loop through the array in the worse case and will return early if if finds something.

How to find MAX number in unseen array using for loop?

This is the solution to the problem. What I don't understand is why is it not "if ( i > currentMax)? I also don't understand the nature of numbers[i]. I understand we can reference indexes in arrays doing numbers[0], but numbers[i] is confusing me.
function max(numbers) {
let currentMax = numbers[0];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] > currentMax) {
currentMax = numbers[i];
}
}
return currentMax;
}
numbers[i] refers to the value stored at position i. If you were to use if (i > currentMax) then you would always return the last element, since the last element always has the greatest index.
Don't reinvent the wheel, use Math.max(...numbers).
Say you have an array like:
[1, 2, 4, 2]
This starts by setting currentMax numbers[0] which is one. Then it loops through the array one element at a time. If it finds a larger number during that loop — in other words if (numbers[i] > currentMax) then it sets the currentMax that number instead. For example this will happen the second and thirds times through the loop when i equals 2 & 4. But it won't happen the last time through the loop. An easy way to watch this happen is to print some stuff to the console as it runs:
function max(numbers) {
let currentMax = numbers[0];
for (let i = 0; i < numbers.length; i++) {
console.log("i:", i, "element:", numbers[i], "max:", currentMax)
if (numbers[i] > currentMax) {
currentMax = numbers[i];
console.log("new currentMax:", currentMax)
}
}
return currentMax;
}
max([1, 2, 4, 2])
In this case i is an "index" which allows us to iterate over all the positions in the array (and accessing their values). In this case i=0, i=1,..., i=numbers.length,
if (numbers[i] > currentMax) asks if the number stored in the array in the position i is greater than the currentMax value. This guarantees that from the provided array the maximum number is returned.
If you ask if (i > currentMax) you compare the value of the "index" (i) with the value of the currentMax value. This is incorrect if you want to return the greatest value from an array of numbers.
Like you said, you can reference indexes in arrays by doing numbers. Instead of hard coding numbers you can use a variable that has a number as a value.
function max(numbers) {
// get the value in the first place in the array
let currentMax = numbers[0];
// create a variable called i
// set it to 0
// loop through, increasing i each time, for as long as i is less than the length of the array
// the first time through i = 0
// the second time through i = 1
// then i = 2
// ... repeat until the end
for (let i = 0; i < numbers.length; i++) {
// get the value from the array at the i place
// if it is greater than the current max
if (numbers[i] > currentMax) {
// then set current max to it
currentMax = numbers[i];
}
}
// return current max
return currentMax;
}

Insertion Sort Algorithm on JavaScript

I recently started learning algorithms based on the book Data Structures and Algorithms with JavaScript from O'Reilly.
I stopped on Chapter 12 - Sorting Algorithms.
I can not understand how Insertion Sort works.
Here is the code I am working with: pasteBin - Insertion Sort
Below is the part that is confusing to me:
function insertionSort() {
var temp, inner;
for (var outer = 1; outer <= this.dataStore.length - 1; ++outer) {
temp = this.dataStore[outer];
inner = outer;
while (inner > 0 && (this.dataStore[inner-1] >= temp)) {
this.dataStore[inner] = this.dataStore[inner-1];
--inner;
}
this.dataStore[inner] = temp;
}
console.log(this.toString());
}
Could anyone help and comment on this code?
It's a sorting algorithm which starts at the beginning of the array and passes through until the end. For the item at each index, it goes back through the items at earlier indices and checks to see if it should be placed before them. If so, it swaps indices with the larger value until it settles into the index it should have.
Here's the code with some commentary, hopefully it is helpful to you.
function insertionSort() {
/* Set up local vars */
var temp, inner;
/* Start at index 1, execute outer loop once per index from 1 to the last index */
for (var outer = 1; outer <= this.dataStore.length - 1; ++outer) {
/* Store the value at the current index */
temp = this.dataStore[outer];
/* Set up temporary index to decrement until we find where this value should be */
inner = outer;
/* As long as 'inner' is not the first index, and
there is an item in our array whose index is less than
inner, but whose value is greater than our temp value... */
while (inner > 0 && (this.dataStore[inner-1] >= temp)) {
/* Swap the value at inner with the larger value */
this.dataStore[inner] = this.dataStore[inner-1];
/* Decrement inner to keep moving down the array */
--inner;
}
/* Finish sorting this value */
this.dataStore[inner] = temp;
}
console.log(this.toString());
}
Here is a jsfiddle with lots of console printouts so you can step through it and see what happens at each step.
The main concept behind insertion sort is to sort elements by comparison.
The comparison occurs in your case for a dataStore array, containing what we assume to be comparable elements such as numbers.
In order to compare element by element, this insertion sort algorithm starts at the beginning of the dataStore array and will continue to run until the end of the array has been reached. This is accomplished by a for loop:
for (var outer = 1; outer <= this.dataStore.length - 1; ++outer)
As the algorithm goes through each element in order, it will:
Store the current element we are visiting in the array in a variable called temp.
Keep track of the location we are in the array via the inner and outer variables, where:
outer is our counter.
inner is a flag to determine whether or not we are visiting the first element in the array. Why is this important? Because there is no point in doing a comparison on the first element, on the first try.
It will compare the current element temp with each element that came before it in the dataStore array. This is accomplished by an inner while loop as seen here:
while (inner > 0 && (this.dataStore[inner-1] >= temp))
This tells you that, as long as all previous visited elements in the dataStore array are greater than or equal to temp, our temporary variable used to store the current element; we want to swap these values.
Swapping them will accomplish the following:
Assume all elements before this.dataStore[inner] are greater than 10, and the currently visited element this.dataStore[inner] equals 5. This logically means that 5 needs to be at the beginning of the array. In such case we would continue to pass 5 all the way down to this.datastore[0] thanks to the while loop. Thus making 5 the first element in the array.
At the end of this swapping, the value in temp is placed accordingly to the current position we are in the array, just to remind you which position this is, it's stored the variable outer.
TLDR: I also like Justin Powell's answer as it sticks with the code, but I thought a walk through would be more useful depending on your level of understanding. I hope it helps!
Starting from the inner loop check if the current element is greater than the previous if yes, exit the loop since everything is sorted for the iteration, if not swap elements because the current needs to be moved to the left because it's smaller than the previous. The inner loop makes sure to swap elements until you encounter a sorted element which results with the break exiting the loop.
After the swap occurs decrease the outer index (i) since you are going downwards to check if the upcoming element is lesser than the previous, you cannot keep the outer index (i) static.
At last, the memIndex variable serves as a reset index because at the end of your inner loop you want to move to the next index. Index (i) should always be placed at the last element of the sorted array so that the inner loop can start the comparison again.
function insertionSort(arr) {
let memIndex = 0
for (let i = 0; i < arr.length; i++) {
memIndex = i;
for (let j = i + 1; j >= 0; --j) {
if (arr[j] >= arr[i]) {
break;
}
if (arr[j] < arr[i]) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i = i - 1;
}
}
i = memIndex;
}
return arr;
}
const arr = [5, 1, 6, 2, 4, 9, 9, 3, 1, 1, 1];
console.log('Unsorted array', arr);
console.log('Sorted array:', insertionSort(arr));
const insertionSort = array => {
const arr = Array.from(array); // avoid side effects
for (let i = 1; i < arr.length; i++) {
for (let j = i; j > 0 && arr[j] < arr[j - 1]; j--) {
[arr[j], arr[j - 1]] = [arr[j - 1], arr[j]];
}
}
return arr;
};
insertion sort means first step we are going to take one value from unsorted sublets and second step we are going to find out appropriate place for that in sorted sublet after find out right place we will insert that value in sorted sublet.
you can get deep understanding from this video links:-
Insertion Sort Algorithm | Data Structure
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
// first step
let currentValue = arr[i]
let j
for (j = i - 1; j >= 0 && arr[j] > currentValue; j--) {
// second step
arr[j + 1] = arr[j]
}
arr[j + 1] = currentValue
}
return arr
}
console.log(insertionSort([5,2,6,3,1,4]))

Is this the right way to iterate through an array?

Here is the code in question:
var L1 = [];
var Q1 = [];
function populateListOne() {
var limit = prompt("please enter a number you would like to fill L1 to.");
for (i = 2; i <= limit; i++) {
L1[i] = i;
}
for (n = 2; n <= L1.length; n++) {
var count = 2;
if (n == count) {
var index = L1.indexOf(n);
L1.splice(index, 1);
Q1[n] = n;
count = count + 1;
}
for (j = 0; j <= L1.length; j++) {
if (L1[j] % 2 == 0) {
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
}
document.getElementById("demo").innerHTML = "iteration " + "1" + ": " + L1 + " Q1 = " + Q1;
}
I’m currently working on a homework assignment where I have to setup a queue. All is explained in my JSFiddle.
Problem description
Essentially, the part I’m stuck on is iterating through each instance of the array and then taking the value out if the modulus is identical to 0. However, as you can see when I run the program, it doesn’t work out that way. I know the problem is in the second for loop I just don’t see what I’m doing wrong.
The way I read it is, if j is less than the length of the array, increment. Then, if the value of the index of L1[j] modulus 2 is identical to 0, set the value of secondIndex to whatever the index of j is. Then splice it out. So, theoretically, only numbers divisible by two should be removed.
Input
A single number limit, which will be used to fill array L1.
L1 will be initialized with values 2, 3, ... limit.
Process
Get the starting element of array L1 and place it in array Q1.
Using that element, remove all values in array L1 that are divisible by that number.
Repeat until array L1 is empty.
You're going to have issues with looping over an array if you're changing the array within the loop. To help with this, I tend to iterate from back to front (also note: iterate from array.length - 1 as the length element does not exist, arrays are key'd from 0):
for(j = L1.length - 1; j >=0 ; j--)
For your first loop, you miss the elements L1[0] and L1[1], so I would change the first loop to:
L1 = [];
for(i = 2; i <= limit; i++)
{
L1.push(i);
}
In this section:
for(j = 0; j <= L1.length; j++){
if(L1[j] % 2 == 0)
{
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
you should splice with j instead of secondIndex.
Change L1.splice(secondIndex, 1); to L1.splice(j, 1);
Array indices and putting entries
You initial code used an array that was initialized to start at index 2. To avoid confusion, of what index to start at, start with index 0 and iterate until array.length instead of a predefined value limit to ensure that you go through each element.
The following still works but will be more of a headache because you need remember where to start and when you will end.
for (i = 2; i <= limit; i++) {
L1[i] = i; // 'i' will begin at two!
}
Here's a better way:
for (i = 2; i <= limit; i++) {
// 'i' starts at 2 and since L1 is an empty array,
// pushing elements into it will start index at 0!
L1.push(i);
}
Use pop and slice when getting values
When you need to take a peek at what value is at the start of your array, you can do so by using L1[0] if you followed my advice above regarding array keys.
However, when you are sure about needing to remove the starting element of the array, use Array.slice(idx, amt). idx specifies which index to start at, and amt specifies how many elements to remove beginning at that index (inclusive).
// Go to 1st element in L1. Remove (1 element at index 0) from L1.
var current = L1.splice(0, 1);
Use the appropriate loops
To make your life easier, use the appropriate loops when necessary. For loops are used when you know exactly how many times you will iterate. Use while loops when you are expecting an event.
In your case, 'repeat until L1 is empty' directly translates to:
do {
// divisibility checking
} while (L1.length > 0);
JSFiddle
Here's a complete JS fiddle with in-line comments that does exactly what you said.

Javascript loop infinitely up till a certain condition

// Contains a list of items in each set.
var sets[0] = [1,2,3,4,5,6,7,8,9],
sets[1] = [10,11,12,13,14,15,16,17,18],
sets[2] = [19,20,21,22,23,25,26,27]
// Contains the mins associated to each set item.
var setTimes[0] = [15,15,15,15,15,15,15,15,15],
setTimes[1] = [16,12,11,15,13,15,15,15,14],
setTimes[2] = [16,12,11,15,13,12,11,15,13]
I've got a set of arrays as given above. The sets array has a data set of values. This array can have n number of items in it. Ex, sets[n].
Each sets array has an equivalent setTimes array that has minutes stored in it. setTimes[0][0] is 15min and is the number of minutes for sets[0][0].
Given a set item(ex 12), I'd like to:
Find out which set array does the given number belong to? In our case, since 12 was the item, it belongs to sets[1].
Once I have this, I'd like to get the sum of all mins from the setTimes array for the current sets index and also the next index. In our case, that would be the sum of setTimes[1] and setTimes[2].
In the event we reach the end of sets array, I'd like to get the sum of the first set array.
For ex,
- if I pass 12, I'll need to get the sum of setTimes[1] and setTimes[2]
- If I pass 23, I'll need to get the sum of setTimes[2] and setTimes[0]
Here is the loop I've been thinking, would like to know if there is a better way of doing this.
function computeTotalMin(givenItem)
{
// represents how many sets to loop thorough. I need 2.
for (x = 0; x <= 1; x++)
{
for(i = 0; i < sets.length; i++)
{
// checking to see if i value is on the last index of the sets array.
if(i === sets.length - 1)
{
i = 0;
var item = sets[i].indexOf(givenItem);
if(item !== -1)
{
// Loops through all mins from setTimes[i] array
for(j = 0; j < setTimes[i].length; j++)
{
var total = total + setTimes[j];
}
}
}
}
}
}
You don't need two nested loops for continuing at the end. You should have a single loop that iterates the number of sets you're interested in (2), and has an index (starting at the one set you've found). Inside that loop, you'd make a modulo operation on the index; to get back to the start when you've reached the end. By only looping over the count, not the (resettable) index, you won't get into an infinite loop.
You also should divide your program in just those tasks that you've textually described (find this, then do that), instead of munching everything in one huge nested control structure.
function computeTotalMin(givenItem) {
var setIndex = -1;
for (; setIndex < sets.length; setIndex++)
if (sets[setIndex].indexOf(givenItem) > -1)
break;
if (setIndex == sets.length)
return null; // givenItem found in none of the sets
var sum = 0;
for (var count = 0; count < 2; count++) {
for (var i=0; i<setTimes[setIndex].length; i++)
sum += setTimes[setIndex][i];
setIndex++; // go to next set
setIndex %= sets.length; // which might be 0
// alternatively: if (setIndex == sets.length) setIndex = 0;
}
return sum;
}

Categories

Resources