can anyone tell me what is this code for? - javascript

can anyone tell me what is this code for?
especially this line of code, I can't understand this line
ctr[arr[i] - 1]++;
function array_element_mode(arr) {
var ctr = [],
ans = 0;
for (var i = 0; i < 10; i++) {
ctr.push(0);
}
for (var i = 0; i < arr.length; i++) {
// what is this code for??
ctr[arr[i] - 1]++;
if (ctr[arr[i] - 1] > ctr[ans]) {
ans = arr[i] - 1;
}
}
return ans + 1;
}
console.log(array_element_mode([1, 2, 3, 2, 2, 8, 1, 9]))

I believe that this function is supposed to return the mathematical mode of an array.
I just added/fixed some variable names to your function. This is still a terrible implementation but I'm hoping that the edits will make what it does more clear to you.
function array_element_mode2(arr) {
var center = [],
mode = 0;
for (let i = 0; i < 10; i++) {
center.push(0);
}
for (let i = 0; i < arr.length; i++) {
const priorElementOfArr = arr[i] - 1;
center[priorElementOfArr]++;
if (center[priorElementOfArr] > center[mode]) {
mode = priorElementOfArr;
}
}
return mode + 1;
}

I renamed the varibles and splitted ctr[arr[i] - 1]++; into two lines. This functions is supposed to find the number which appears most in a given array of integers.
But it wont work if two or more integers appear the same number of times and if the array contains 0.
/*
* Goal: Find the number which appears most in a given array of integers
* Solution: In the ctr array store the number apperences in the following way
* ctr[0] appearances of "1" in the array
* ctr[1] appearances of "2" in the array
* ctr[2] appearances of "3" in the array
* ...
*/
function array_element_mode(arr) {
var ctr = [],
ans = 0;
// fill the ctr array with nulls
for (var i = 0; i < 10; i++) {
ctr.push(0);
}
for (var i = 0; i < arr.length; i++) {
//////////// here the ctr[arr[i] - 1]++; is splitted into 2 lines
// for each array member "find" the correct index to increase
const convertArrayMemberToIndexForCtr = arr[i] - 1;
// increase the correct index by one
ctr[convertArrayMemberToIndexForCtr]++;
///////////
// check if the increased index if larger then current answer and if so
// store it as the new result
if (ctr[convertArrayMemberToIndexForCtr] > ctr[ans]) {
ans = convertArrayMemberToIndexForCtr;
}
}
// return the result, but not the index we created before (on line 25), but the real number that is in the array (add the +1 we subtracted before)
return ans + 1;
}
console.log('working example');
console.log(array_element_mode([1, 2, 3, 2, 2, 8, 1, 9]));
console.log('this wont work, it shows that "3" is the result, ignoring the "2"');
console.log(array_element_mode([3, 3, 3, 2, 2, 2, 5, 9]));
console.log('this wont work as index arr[i] - 1 would then be 0-1=-1');
console.log(array_element_mode([0, 1, 1, 0, 0, 4, 5, 9]));
console.log('this wont work, all integers are only once in the array');
console.log(array_element_mode([1, 2, 3, 4, 5, 6, 7, 8]));

I think this function is to find out which element has the most number in the array
ctr[arr[i] - 1]++:In order to count

Related

I need to know regarding this question related to prefix sum

var subarraySum = function(nums, k) {
let obj = {
0: 1
};
let count = 0;
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
if (obj[sum - k]) {
count += obj[sum - k];
}
obj[sum] = ++obj[sum] || 1;
}
return count;
};
console.log(subarraySum([1, 2, 3, 3, 2, 1, 3], 4))
console.log(subarraySum([1, 2, 3, 3, 2, 1, 3], 5))
Question statement: Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k. A subarray is a contiguous non-empty sequence of elements within an array.
Why did we define obj as {0 : 1}?
And what exactly is happening when you write obj[sum-k]?
More comments in the code. First I simplified some statements meant to confuse. Then we are left with the pure algorithm. The idea is keeping a total and all the totals we have so far as "seen before". If at any point we find current total to be "seen before" + k it means we found a total k sub group
var subarraySum = function(nums, k) {
// obj counts true or false for *every* sum we accomulate
let obj = {
0: 1
};
let count = 0;
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
// if we encounter a seen before difference between sum and k
// it means we have a "sum-k subgroup" thus far.
// example:
// consider we encounterd 1, 2, 3, 4 so we encounterd 10, right?
// we keep going then we a point of sum 15
// it means we must have since the last 10 found a subgroup of sum 5
if (obj[sum - k]) {
// so we found one
count++
}
// mark current sum as encountered = true
obj[sum] = 1;
}
return count;
};
console.log(subarraySum([1, 2, 3, 3, 2, 2, 1, 3], 5))
.as-console-wrapper {
max-height: 100% !important
}

LeetCode 768: Constructing a variation on a solution for Max Chunks To Make Sorted

LeetCode's Max Chunks To Make Sorted II challenge is:
Given an array arr of integers (not necessarily distinct), we split
the array into some number of "chunks" (partitions), and individually
sort each chunk. After concatenating them, the result equals the
sorted array.
What is the most number of chunks we could have made?
Example:
Input: arr = [2, 1, 3, 4, 4]
Output: 4
Explanation:
We can split into two chunks, such as [2, 1], [3, 4, 4].
However, splitting into [2, 1], [3], [4], [4] is the highest number of chunks possible.
The algorithm underlying the following solution is (the algorithm and the solution were posted as a comment on the solution page by a user named #benevolent. Unfortunately, I can't link to its comment):
If the largest number from arr[0] to (including) arr[k] is less than or equal to the smallest
number from arr[k+1] to the end, then we can split into two valid
chunks.
To illustrate:
left right
[......max] [min......]
To know the minimum element from k to arr.length-1, we can just
precompute from right to left.
The solution:
function maxChunksToSorted(arr) {
var minRight = Array(arr.length).fill(Number.MAX_SAFE_INTEGER);
for (var i = arr.length-2; i >= 0; --i) {
minRight[i] = Math.min(minRight[i+1], arr[i+1]);
}
var maxLeft = Number.MIN_SAFE_INTEGER;
var ans = 0;
for (var i = 0; i < arr.length; ++i) {
maxLeft = Math.max(maxLeft, arr[i]);
if (maxLeft <= minRight[i]) {
ans += 1
}
}
return ans;
};
console.log("expects: 1", "got:", maxChunksToSorted([5, 4, 3, 2, 1]));
console.log("expects: 4", "got:", maxChunksToSorted([2, 1, 3, 4, 4]));
My question:
I was trying to make a "mirror image" of the above solution, by "flipping" every action (e.g, the use of min becomes max, <= becomes >, and so on).
My maxArr indeed mirrors minRight (e.g., for [2, 1, 3, 4, 4], my maxArr is [MIN_SAFE_INTEGER, 1, 3, 4, 4], while the original minRight is [1, 3, 4, 4, MAX_SAFE_INTEGER]), but it clearly doesn't work, and I can't put my finger on the reason for that.
What's my fundamental problem?
Let me stress that I'm not looking for some other working solution. I'd like to understand what went wrong with my mirror solution, if it's even possible to make this mirror, and if not - what's the fundamental reason for that.
function maxChunksToSorted(arr) {
var maxArr = Array(arr.length).fill(Number.MIN_SAFE_INTEGER);
for (var i = 1; i <= arr.length; ++i) {
maxArr[i] = Math.max(maxArr[i-1], arr[i]);
}
var minLeft = Number.MAX_SAFE_INTEGER;
var ans = 0;
for (var i = 0; i < arr.length; ++i) {
minLeft = Math.min(minLeft, arr[i]);
if (minLeft > maxArr[i]) {
ans += 1
}
}
return ans;
};
console.log("expects: 1", "got:", maxChunksToSorted([5, 4, 3, 2, 1]));
console.log("expects: 4", "got:", maxChunksToSorted([2, 1, 3, 4, 4]));
This should do the job:
function chunk(list){
let sortedList = list.slice();
sortedList.sort();
var beginIndex = -1; var biggestFound;
var foundFirst = false; var foundLast = false;
for(var i = 0; i < list.length; i++){
if(beginIndex == -1) {
if(list[i] == sortedList[i]) print(list[i]);
else {beginIndex = i; biggestFound = list[i];}
}
else{
if(list[i] == sortedList[beginIndex]) foundFirst = true;
if(list[i] > biggestFound) biggestFound = list[i];
if(biggestFound == sortedList[i]) foundLast = true;
if(foundFirst && foundLast){
print(list.slice(beginIndex, i - beginIndex + 1));
foundFirst = false; foundLast = false; beginIndex = -1;
}
}
}
}
chunk([2,1,3,4,4]);
As I commented, if a chunk starts at position i, it must contain the element that corresponds to the position i in the sorted array and if it ends in position j, it must contain the element in the index j of the sorted array.
When both of these conditions are satisfied, you close the chunk and start a new one.
The complexity is O(n lg(n)), where n is the size of the array.

Mini-Max Sum HACKERHANK JS, why isn't working?

I don't know what's wrong, my function miniMaxSum isn't summing 1+3+4+5. At the end, the result array turns into this [ 14, 12, 11, 10 ], when it should looks like this [ 14, 13, 12, 11, 10 ]
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex) continue;
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = 0;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
console.log(miniMaxSum([1, 2, 3, 4, 5]));
You're over-complicating your algorithm by trying to check whether you should add the current number to the overall sum or not. Instead, all you need to do is run a loop over your array, to sum up all your elements in your array. This will give you the total sum of all your elements. Then, again, iterate through your array. For each element in your array subtract it from the sum you just calculated and push it into a new array. This will give you the sum if you were to not use the number in the ith position. You can then find the min/max of this using JavaScript's Math.min and Math.max functions.
Here is an example using .reduce() and .map() to calculate the final result:
const miniMaxSum = arr => {
const sum = arr.reduce((s, n) => n+s, 0)
const results = arr.map(n => sum - n);
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
If you prefer standard for loops, here is an implementation of the above in a more imperative style:
const miniMaxSum = arr => {
let sum = 0;
for(let i = 0; i < arr.length; i++) { // sum all elements
sum += arr[i];
}
let results = [];
for(let i = 0; i < arr.length; i++) {
results[i] = sum - arr[i]; // sum minus the current number
}
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
Assuming you're talking about this question.
Whenever you want to restart the loop, you're setting i=0 but observe that you also have increment statement i++ in for loop so, effectively i starts from 1, not 0. You need to set i=-1 so that i=-1+1 = 0 in subsequent iteration. After doing this, you need to handle a corner case. When skipIndex==arr.length-1, check if i == arr.length-1. If yes, do results.push(actualValue); for the last value and then for loop terminates because i < arr.length is false in next iteration.
Code:
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex){
if(i == arr.length - 1)
results.push(actualValue);
continue;
}
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = -1;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
miniMaxSum([1, 2, 3, 4, 5]);
Output
[ 14, 13, 12, 11, 10 ]
10 14

Identify longest period of variance in an array of integers

I'm trying to write a function that will identify the longest period of variance in an array of numbers. Variance begins when the previous number is higher than the current, and ends when the next number is the same as the current; however, if variance doesn't end, then it is assumed the variance began with the last two numbers.
For example: [10, 5, 3, 11, 8, 9, 9, 2, 10] The longest period of variance in this array is [5, 3, 11, 8, 9], or just 5 (the length). A variance ends when the following number is the same as the current, in this case, 9.
The function I've written works on this case; however, it doesn't when the entire array has variance, such as [10, 5, 10, 5, 10, 5, 10, 5, 10], which returns 8, when it should be 9.
In the case where the previous number is number is always lower, or always higher than the variance would be 2, because it never ended. For example [2, 4, 6, 8] and [8, 6, 4, 2].
I know the issue with the entire array variance can be solved by starting the for loop at 0, but then the other cases become invalid. Any help is greatly appreciated.
Without further ado, here is my code:
function findVariance(numbers) {
if ([0,1].includes(numbers.length)) return numbers.length;
const variance = [[0]];
let greater = numbers[1] > numbers[0];
let lesser = numbers[1] < numbers[0];
for (let i = 1; i < numbers.length; i++) {
let previous = variance.length - 1;
let previousVarianceGroup = variance[previous];
let previousVarianceGroupValue = previousVarianceGroup[previousVarianceGroup.length - 1];
if (greater) {
if (numbers[i] < numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = false;
lesser = true;
} else {
greater = numbers[i] < numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else if (lesser) {
if (numbers[i] > numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = true;
lesser = false;
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] > numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
}
const result = [];
for (let i = 0; i < variance.length; i++) {
result[i] = variance[i].length;
}
result.sort();
return result[result.length - 1];
}
console.log(findVariance([10, 5, 3, 11, 8, 9, 9, 2, 10]));
console.log(findVariance([10, 5, 10, 5, 10, 5, 10, 5, 10]));
console.log(findVariance([2, 4, 6, 8]));
Here's what I got (trying to understand the question as best i could)
function calculateVariance(arr) {
// trivial cases
if (arr.length <= 1) { return arr.length; }
// store the difference between each pair of adjacent numbers
let diffs = [];
for (let i = 1; i < arr.length; i++) {
diffs.push(arr[i] - arr[i - 1]);
}
let max = 0;
// if the difference between two numbers is 0, they're the same.
// the base max variance encountered is 1, otherwise it's 2.
// the boolean zen here is that diffs[0] is falsy when it's 0, and truthy otherwise
let count = diffs[0] ? 2 : 1;
// go through the array of differences,
// and count how many in a row are alternating above/below zero.
for (i = 1; i < diffs.length; i++) {
if ((diffs[i] < 0 !== diffs[i - 1] < 0) && diffs[i] && diffs[i - 1]) {
count++;
} else {
max = Math.max(count, max);
// see above
count = diffs[i] ? 2 : 1;
}
}
// account for the maximum variance happening at the end
return Math.max(count, max);
}
You are overcomplicating things a bit, just increase a counter as long as an element equals the next one, reset on equal:
const counts = [];
let count = 0;
for(let i = 0; i < numbers.length - 1; i++) {
if(numbers[i] === numbers[i + 1]) {
counts.push(count);
count = 0;
} else {
count++;
}
}
counts.push(count);
return counts.sort()[counts.length - 1];

Find the first repeated number in a Javascript array

I need to find first two numbers and show index like:
var arrWithNumbers = [2,5,5,2,3,5,1,2,4];
so the first repeated number is 2 so the variable firstIndex should have value 0. I must use for loop.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var firstIndex
for (i = numbers[0]; i <= numbers.length; i++) {
firstIndex = numbers[0]
if (numbers[i] == firstIndex) {
console.log(firstIndex);
break;
}
}
You can use Array#indexOf method with the fromIndex argument.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
// iterate upto the element just before the last
for (var i = 0; i < numbers.length - 1; i++) {
// check the index of next element
if (numbers.indexOf(numbers[i], i + 1) > -1) {
// if element present log data and break the loop
console.log("index:", i, "value: ", numbers[i]);
break;
}
}
UPDATE : Use an object to refer the index of element would make it far better.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
ref = {};
// iterate over the array
for (var i = 0; i < numbers.length; i++) {
// check value already defined or not
if (numbers[i] in ref) {
// if defined then log data and brek loop
console.log("index:", ref[numbers[i]], "value: ", numbers[i]);
break;
}
// define the reference of the index
ref[numbers[i]] = i;
}
Many good answers.. One might also do this job quite functionally and efficiently as follows;
var arr = [2,5,5,2,3,5,1,2,4],
frei = arr.findIndex((e,i,a) => a.slice(i+1).some(n => e === n)); // first repeating element index
console.log(frei)
If might turn out to be efficient since both .findIndex() and .some() functions will terminate as soon as the conditions are met.
You could use two for loops an check every value against each value. If a duplicate value is found, the iteration stops.
This proposal uses a labeled statement for breaking the outer loop.
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
i, j;
outer: for (i = 0; i < numbers.length - 1; i++) {
for (j = i + 1; j < numbers.length; j++) {
if (numbers[i] === numbers[j]) {
console.log('found', numbers[i], 'at index', i, 'and', j);
break outer;
}
}
}
Move through each item and find if same item is found on different index, if so, it's duplicate and just save it to duplicate variable and break cycle
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var duplicate = null;
for (var i = 0; i < numbers.length; i++) {
if (numbers.indexOf(numbers[i]) !== i) {
duplicate = numbers[i];
break; // stop cycle
}
}
console.log(duplicate);
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var map = {};
for (var i = 0; i < numbers.length; i++) {
if (map[numbers[i]] !== undefined) {
console.log(map[numbers[i]]);
break;
} else {
map[numbers[i]] = i;
}
}
Okay so let's break this down. What we're doing here is creating a map of numbers to the index at which they first occur. So as we loop through the array of numbers, we check to see if it's in our map of numbers. If it is we've found it and return the value at that key in our map. Otherwise we add the number as a key in our map which points to the index at which it first occurred. The reason we use a map is that it is really fast O(1) so our overall runtime is O(n), which is the fastest you can do this on an unsorted array.
As an alternative, you can use indexOf and lastIndexOf and if values are different, there are multiple repetition and you can break the loop;
function getFirstDuplicate(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) !== arr.lastIndexOf(arr[i]))
return arr[i];
}
}
var arrWithNumbers = [2, 5, 5, 2, 3, 5, 1, 2, 4];
console.log(getFirstDuplicate(arrWithNumbers))
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11]
console.log(getFirstDuplicate(numbers))
I have the same task and came up with this, pretty basic solution:
var arr = [7,4,2,4,5,1,6,8,9,4];
var firstIndex = 0;
for(var i = 0; i < arr.length; i++){
for( var j = i+1; j < arr.length; j++){
if(arr[i] == arr[j]){
firstIndex = arr[i];
break;
}
}
}
console.log(firstIndex);
First for loop takes the first element from array (number 7), then the other for loop checks all other elements against it, and so on.
Important here is to define j in second loop as i+1, if not, any element would find it's equal number at the same index and firstIndex would get the value of the last one after all loops are done.
To reduce the time complexity in the aforementioned answers you can go with this solution:
function getFirstRecurringNumber(arrayOfNumbers) {
const hashMap = new Map();
for (let number of arrayOfNumbers) { // Time complexity: O(n)
const numberDuplicatesCount = hashMap.get(number);
if (numberDuplicatesCount) {
hashMap.set(number, numberDuplicatesCount + 1);
continue;
}
hashMap.set(number, 1); // Space complexity: O(n)
}
for (let entry of hashMap.entries()) { // Time complexity: O(i)
if (entry[1] > 1) {
return entry[0];
}
}
}
// Time complexity: O(n + i) instead of O(n^2)
// Space complexity: O(n)
Using the code below, I am able to get just the first '5' that appears in the array. the .some() method stops looping through once it finds a match.
let james = [5, 1, 5, 8, 2, 7, 5, 8, 3, 5];
let onlyOneFives = [];
james.some(item => {
//checking for a condition.
if(james.indexOf(item) === 0) {
//if the condition is met, then it pushes the item to a new array and then
//returns true which stop the loop
onlyOneFives.push(item);
return james.indexOf(item) === 0;
}
})
console.log(onlyOneFives)
Create a function that takes an array with numbers, inside it do the following:
First, instantiate an empty object.
Secondly, make a for loop that iterates trough every element of the array and for each one, add them to the empty object and check if the length of the object has changed, if not, well that means that you added a element that already existed so you can return it:
//Return first recurring number of given array, if there isn't return undefined.
const firstRecurringNumberOf = array =>{
objectOfArray = {};
for (let dynamicIndex = 0; dynamicIndex < array.length; dynamicIndex ++) {
const elementsBeforeAdding = (Object.keys(objectOfArray)).length;0
objectOfArray[array[dynamicIndex]] = array[dynamicIndex]
const elementsAfterAdding = (Object.keys(objectOfArray)).length;
if(elementsBeforeAdding == elementsAfterAdding){ //it means that the element already existed in the object, so it didnt was added & length doesnt change.
return array[dynamicIndex];
}
}
return undefined;
}
console.log(firstRecurringNumberOf([1,2,3,4])); //returns undefined
console.log(firstRecurringNumberOf([1,4,3,4,2,3])); //returns 4
const arr = [1,9,5,2,3,0,0];
const copiedArray = [...arr];
const index = arr.findIndex((element,i) => {
copiedArray.splice(0,1);
return copiedArray.includes(element)
})
console.log(index);
var addIndex = [7, 5, 2, 3, 4, 5, 7,6, 2];
var firstmatch = [];
for (var i = 0; i < addIndex.length; i++) {
if ($.inArray(addIndex[i], firstmatch) > -1) {
return false;
}
firstmatch.push(addIndex[i]);
}

Categories