I need to know regarding this question related to prefix sum - javascript

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
}

Related

can anyone tell me what is this code for?

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

Can someone explain me how does this javascript code works please?

Given a JavaScript function that takes in an array of numbers as the first and the only argument.
The function then removes one element from the array, upon removal, the sum of elements at odd indices is equal to the sum of elements at even indices. The function should count all the possible unique ways in which we can remove one element at a time to achieve balance between odd sum and even sum.
Example var arr = [2, 6, 4, 2];
Then the output should be 2 because, there are two elements 6 and 2 at indices 1 and 3 respectively that makes the combinations table.
When we remove 6 from the array
[2, 4, 2] the sum at odd indexes = sum at even indexes = 4
if we remove 2
[2, 6, 4] the sum at odd indices = sum at even indices = 6
The code below works perfectly. There might be other solutions but I want to understand this one, because I feel there is a concept I have to learn here. Can someone explain the logic of this algorithm please?
const arr = [2, 6, 4, 2];
const check = (arr = []) => {
var oddTotal = 0;
var evenTotal = 0;
var result = 0;
const arraySum = []
for (var i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
evenTotal += arr[i];
arraySum[i] = evenTotal
}
else {
oddTotal += arr[i];
arraySum[i] = oddTotal
}
}
for (var i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
if (arraySum[i]*2 - arr[i] + oddTotal === (arraySum[i - 1] || 0)*2 + evenTotal) {
result = result +1
};
} else if (arraySum[i]*2 - arr[i] + evenTotal === (arraySum[i - 1] || 0)*2 + oddTotal) {
result = result +1
}
}
return result;
};

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

Product of all other numbers in array

I have a function which takes an array of numbers as an argument. I want to return a new array with the products of each number except for the number at the current index.
For example, if arr had 5 indexes and we were creating the value for index 1, the numbers at index 0, 2, 3 and 4 would be multiplied.
Here is the code I have written:
function getProducts(arr) {
let products = [];
for(let i = 0; i < arr.length; i++) {
let product = 0;
for(let value in arr.values()) {
if(value != arr[i]) {
product *= value;
}
}
products.push(product);
}
return products;
}
getProducts([1, 7, 3, 4]);
// Output ➞ [0, 0, 0, 0]
// Expected output ➞ [84, 12, 28, 21]
As you can see, the desired output does not actualise. I did some experimenting and it appears that the second for loop is never really initiated, as any code I put inside the block does not execute:
function getProducts(arr) {
let products = [];
for(let i = 0; i < arr.length; i++) {
let product = 0;
for(let value in arr.values()) {
console.log('hello!');
if(value != arr[i]) {
product *= value;
}
}
products.push(product);
}
return products;
}
getProducts([1, 7, 3, 4]);
// Output ➞
// Expected Output ➞ 'hello!'
What is wrong with my code?
You could take the product of all numbers and divide by the number of the index to get a product of all except the actual value.
function getProducts(array) {
var product = array.reduce((a, b) => a * b, 1);
return array.map(p => product / p);
}
console.log(getProducts([1, 7, 3, 4]));
A more reliable approach with an array with one zero. If an array has more than one zero, all products are zero.
The below approach replaces the value at index with one.
function getProducts(array) {
return array.map((_, i, a) => a.reduce((a, b, j) => a * (i === j || b), 1));
}
console.log(getProducts([1, 7, 0, 4]));
console.log(getProducts([1, 7, 3, 4]));
You simply have to change the in keyword to of keyword. Is not the same a for..in than a for..of.
arr.values() returns an iterator, which has to be iterated with the of keyword.
Also, if product = 0, then all your multiplications will return 0.
By the way this code is prone to error, because you don't check the current index, but you check if the value that you are multiplying is different than the current value. This will lead to a problem if the same number is duplicated in the array.
And, now talking about good practices, is a bit weird that first you iterate through the array with a for(var i... loop and the second time you do it with a for...in/of.
I've fixed the code for you:
function getProducts(arr) {
let products = [];
for(let i = 0; i < arr.length; i++) {
let product = 1;
for(let ii = 0; ii < arr.length; ii++) {
if(i != ii) {
product *= arr[ii];
}
}
products.push(product);
}
return products;
}
A better way to do that is get the total product and use map() to divide total with each value
function getProducts(arr){
let total = arr.reduce((ac,a) => ac * a,1);
return arr.map(x => x === 0 ? total : total/x);
}
console.log(getProducts([1, 7, 3, 4]))
Explanation: replace the number at i with 1 so it doesn't interfere with the multiplication. Also, apply the fill on a copy of a hence the [...a]
console.log( [2,3,4,5].map( (n,i,a) => [...a].fill(1,i,i+1).reduce( (a,b) => a*b ) ) )

Categories