Given five positive integers, find the minimum and maximum values that can be calculated by summing exactly four of the five integers. Then print the respective minimum and maximum values as a single line of two space-separated long integers.
For example, if the array is [1, 3, 5, 7, 9]. Our minimum sum is 1 + 3 + 5 + 7 = 16 and our maximum sum is 3 + 5 + 7 + 9 = 24.
function miniMaxSum(arr) {
let max = arr.reduce((a, b) => a + b, 1);
let min = arr.reduce((a, b) => a + b, 0, arr.length - 1);
console.log(min, max);
}
Right now, the output should be 10, 14 if the array is just [1, 2, 3, 4, 5].
The output I am getting is 15, 16.
The max variable should just add everything starting from index 1 no?
And the min variable I'm not sure if you're able to do this, but my thinking was initialize the starting at index 0 and go up to the end of the array but minus 1 index.
How can I correct this?
You need to identify which 4 of the 5 elements are the largest, and which 4 of the 5 elements are the smallest - or, equivalently, identify which one element is the smallest, and which one element is the largest, and subtract those from the sum of all 5 elements:
function miniMaxSum(arr) {
// fullSum: sum of all items in the array
const fullSum = arr.reduce((a, b) => a + b, 0);
// Find smallest value in array
const min = Math.min(...arr);
// Find largest value in array
const max = Math.max(...arr);
console.log(fullSum - max, fullSum - min);
}
miniMaxSum([1, 3, 5, 7, 9]);
miniMaxSum([1, 2, 3, 4, 5]);
Another approach is to use slice and sum the small and and the large end of the array.
function miniMax(arr) {
const sum = a => a.reduce((a, b) => a + b, 0);
// we can skip the sort if we know the input is sorted, but just in case
const sorted = arr.sort((a,b) => a-b)
const min = sum(sorted.slice(0, sorted.length-1)) // sum the small end of the array
const max = sum(sorted.slice(1)) // sum the large end of the array
return { min, max }
}
console.log(miniMax([1, 3, 5, 7, 9]));
console.log(miniMax([1, 2, 3, 4, 5]));
This only works if the numbers are listed in ascending order in the array
function miniMaxSum(arr)
{
let max = arr.reduce((a,c,i)=>i?a+c:0, 0);
let min = arr.reduce((a,c,i,t)=>i?a+t[i-1]:0, 0);
document.write(`${JSON.stringify(arr)} -> min: ${min}, max: ${max} <br>`);
}
miniMaxSum([1, 3, 5, 7, 9]);
miniMaxSum([1, 2, 3, 4, 5]);
It was fun to do ;)
Related
There is a function that finds the largest sum in a subarray
var maxSubArray = function(nums) {
if(nums.length == 0) return 0;
let result = Number.MIN_SAFE_INTEGER;
let sum = 0;
for(let i = 0; i < nums.length; i++) {
sum += nums[i];
result = Math.max(sum, result);
sum = sum < 0 ? 0 : sum;
}
return result;
};
console.log(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]));
But I cannot understand what is changing and why it stops working if you remove the line: 'result = Math.max(sum, result);'
And change return result to sum
If you comment the result line basically the function won't have memory of previous "candidates to best sum". It will just run over the array adding values to the sum variable, even when it lowers the value of the sum (which you can't avoid and it's useful only if you keep track of the previous best sum candidates).
To further explain, imagine you comment that line and return sum.
Every time the sum turns out to be negative it will be immediately reset to 0. So in your proposed example the final max subarray will be effectively starting to sum up on 4 an will keep summing up if the total sum is greater than zero EVEN if after adding the new value the sum is less than its previous value.
So basically it will go like this:
[-2] // sum = -2. Less than 0, so reset to sum = 0
[-2, 1] // sum = 1
[-2, 1, -3] // sum = -2. Less than 0, so reset to sum = 0
[-2, 1, -3, 4] // sum = 4
[-2, 1, -3, 4, -1] // sum = 3
[-2, 1, -3, 4, -1, 2] // sum = 5
[-2, 1, -3, 4, -1, 2, 1] // sum = 6 BEST SUM
[-2, 1, -3, 4, -1, 2, 1, -5] // sum = 1 :(
[-2, 1, -3, 4, -1, 2, 1, -5, 4] // sum = 5
That's why the variable result is necessary. You have to keep track of the best sum so far and compare it with the "local best", so to speak.
In the original code the state throughout the iterations would look something like this:
[-2]
// sum = -2
// result = -2 because -2 is greater than Number.MIN_SAFE_INTEGER.
// sum = 0. It gets reset because it's negative
[-2, 1]
// sum = 1
// result = 1 because 1 > -2
[-2, 1, -3]
// sum = -2
// result = 1 and isn't updated because the overall max sum so far is greater than the current sum
// sum = 0
[-2, 1, -3, 4]
// sum = 4
// result = 4
[-2, 1, -3, 4, -1]
// sum = 3
// result = 4 and isn't updated because the overall max sum is greater than the current sum
[-2, 1, -3, 4, -1, 2]
// sum = 5
// result = 5
[-2, 1, -3, 4, -1, 2, 1]
// sum = 6 BEST SUM
// result = 6
[-2, 1, -3, 4, -1, 2, 1, -5]
// sum = 1
// result = 6
[-2, 1, -3, 4, -1, 2, 1, -5, 4]
// sum = 5
// result = 6
So as you can see, the final value is now 6 because the overall max sum is persisted in the result variable while sum keeps track of the local best.
This is the implementation of Kadane's Algorithm for Largest Sum Subarray.
The gist of the algo is:
Don't add a subarray which is already summing up to a negative number. This will only decrease the sum further.
Result has to be updated everytime with a subarray's sum having value more than it's current value
For example: This is the output of adding console.log at relevant positions.
Note: Here is the link where you can read more: https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/
It is adding all adjacent elements to get subarray with maximum sum.
In above example the subarray is [4,-1,2,1]
all other subarrays having sum smaller than 6.
I am trying to solve this problem but I don't know why I can't pass all test cases. I need some help and explanation, how can I count some array (in this example: variable s) multiple times and not repeat the same elements that I already summed.
Problem description:
Lily has a chocolate bar that she wants to share it with Ron for his
birthday. Each of the squares has an integer on it. She decides to
share a contiguous segment of the bar selected such that the length of
the segment matches Ron's birth month and the sum of the integers on
the squares is equal to his birth day. You must determine how many
ways she can divide the chocolate.
Consider the chocolate bar as an array of squares, s=[2,2,1,3,2].
She wants to find segments summing to Ron's birth day, d=4 with a
length equalling his birth month, m=2. In this case, there are two
segments meeting her criteria: [2,2] and [1,3].
Function Description
Complete the birthday function in the editor below. It should return
an integer denoting the number of ways Lily can divide the chocolate
bar.
birthday has the following parameter(s):
s: an array of integers, the numbers on each of the squares of
chocolate,
d: an integer, Ron's birth day, m: an integer, Ron's birth month
My code:
function birthday(s, d, m) {
let bars = 0;
if (m !== 1) {
s.reduce((acc, val) => (acc+val) === d ? ++bars : bars)
} else {
bars = 1;
}
return bars;
}
Some cases:
s = [2, 5, 1, 3, 4, 4, 3, 5, 1, 1, 2, 1, 4, 1, 3, 3, 4, 2, 1]
d = 18
m = 7
s = [4, 5, 4, 5, 1, 2, 1, 4, 3, 2, 4, 4, 3, 5, 2, 2, 5, 4, 3, 2, 3,
5, 2, 1, 5, 2, 3, 1, 2, 3, 3, 1, 2, 5]
d = 18
m = 6
s = [4, 5, 4, 2, 4, 5, 2, 3, 2, 1, 1, 5, 4]
d = 15
m = 4
My code works with this:
s = [1, 2, 1, 3, 2]
d = 3
m = 2
This can be found on HackerRank > Practice > Algorithms > Implementation
You just have to slice the array with the sliced length of m, and then compare that to d
As slice doc:
The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included) where start and end represent the index of items in that array. The original array will not be modified.
For example:
s = [1, 2, 1, 3, 2]
m = 2
d = 3
// We loop through s with index stop at s.length - m + 1 for slice to be in correct range
// Slices:
i=0: [1, 2] -> sum=3 -> res=0+1=1
i=1: [2, 1] -> sum=3 -> res=1+1=2
i=2: [1, 3] -> sum=4 -> do nothing
i=4: [3, 2] -> sum=5 -> do nothing
Below is a worked solution
function birthday(s, d, m) {
let res = 0
const sum = (arr) => arr.reduce((acc, el) => acc + el, 0)
for (let i = 0; i < s.length - m + 1; i++) {
if (sum(s.slice(i, i + m)) === d) {
res++
}
}
return res
}
Whenever you are looping over an array to get the summation or do a mathematical equation on it and you have to remove that specific element that you already calculated, You can use one of these built in function to remove an element from an array using a specific index.
Array.prototype.slice()
&& Array.prototype.splice()
Here's an easy to understand way with nested loops:
function birthday(s, d, m) {
var matches = 0; // Total matches found
// Look at chunks starting a position 0. Last chunk can't be m spots past end of array, so last chunk starts at 1 + s.length - m:
for ( let i=0; i < 1 + s.length - m; i++ ) {
var sum = 0; // What this chunk sums to
// Sum up the values of this chunk:
for ( let j=0; j < m; j++ ) {
sum += s[i+j];
}
if ( sum === d ) { // Does this chunk sum to d?
matches++; // Yes!
}
}
return matches;
}
I want to find all possible maximum contiguous subarray averages from an array of values. Each array value represents the value at a duration, the number of seconds passed.
Ex. Input = [6, 4, 3, 10, 5]
Ex. Output = [5.6, 5.75, 6, 7.5, 10]
Output[0] = 6+4+3+10+5 / 5 = 5.6
Output[1] = 6+4+3+10 / 4 = 5.75
Output[2] = 3+10+5 / 3 = 6
Output[3] = 10+5 / 2 = 7.5
Output[4] = 10 / 1 = 10
The issue is that the real data has length of up to 40,000 values.
The result should have the same length as the input. I‘ve done a reduce on a subarray of specific lengths (only getting 5s, 60s, 3600s, etc. length), but that’s not a viable solution for each possible duration. Is there a way I can partition or otherwise create a specialized data structure to get these values? If not, how can I exclude durations as I go?
You can just take the reverse of the input array, then calculate sum and average incrementally. Then again taking the of output array.
const input = [6, 4, 3, 10, 5].reverse();
let output = [];
let total_sum = 0;
for (var i = 0; i < input.length; i++) {
total_sum += input[i];
let avg = total_sum / (i + 1);
output.push(avg);
}
console.log(output.reverse());
(You can even eliminate the reverse by looping the for loop in reverse order.)
Why not .map()? Mixed with reduce you could do something like this:
const output = [
[1, 2, 3, 4],
[5, 6, 7, 8]
];
const averages = output.map(
subarray =>
subarray.reduce(
(previousValue, currentValue) => previousValue + currentValue,
0
) / subarray.length
);
Where subarray is the collection of values, they're then added together and divided by the length of the subarray.
I hope this is what you mean
I need a hand to sum the value of array elements with the previous element(s) and return a new array.
So if we have :
let durations = [4, 3.5, 6];
then in the new array the first element is 4, the second element would be the sum of 4 + 3.5 and the third one would be 4 + 3.5 + 6; so the desired result would be [4, 7.5, 13.5]
So far it seems that reduce unexpectedly just concat the numbers and returns an array of strings !!!
let durations = [4, 3.5, 6];
let arr = [];
let durationsNew = durations.reduce((a, b) => {
arr.push(a + b);
return arr;
}, []);
console.log(durationsNew); // The desired result is [4, 7.5, 13.5]
In your code, you take the accumulator a and add the value to it. The accumulator is an array and this is converted to string by using it with a plus operator.
Instead, you could take a variable for sum and map the sum by adding the value for each element.
let durations = [4, 3.5, 6],
sum = 0,
array = durations.map(value => sum += value)
console.log(array); // [4, 7.5, 13.5]
Try this - a mixture of map() and reduce():
[4, 3.5, 6].map((num, i, arr) =>
num + arr.slice(0, i).reduce((a, b) =>
a + b, 0)); //[4, 7.5, 13.5]
The idea is to map the array to a new array, and for each number, the new number returned is the number + the sum of the array values up to that number.
If you are going to use reduce, you have to do something like this:
let durations = [4, 3.5, 6]
let durationsNew = durations.reduce((_durationsNew, duration, durationIndex) => {
if(durationIndex > 0) {
_durationsNew.push(_durationsNew[durationIndex - 1] + duration)
} else {
_durationsNew.push(duration)
}
return _durationsNew;
}, [])
console.log(durationsNew); // The desired result is [4, 7.5, 13.5]
Example: https://repl.it/repls/HandsomeVacantRate
Benchmark test with Array.map, Array.reduce, and for loop:
This is the HackerRank problem description:
A left rotation operation on an array of size n shifts each of the array's elements d unit to the left. For example, if left rotations are performed on array [1,2,3,4,5], then the array would become [3,4,5,1,2].
Here is my function :
function leftRotation(arr, d) {
let newArr = [];
while (d > 0) {
let first = arr.shift();
newArr.push(first);
d--;
}
return [...arr,...newArr];
}
console.log(leftRotation([1,2,3,4,5], 2))
but it doesn't pass large test cases. For example, for n=73000 and d=60000.
Thanks in advance for any idea .
I'm not entirely sure the performance of this method, but it can be done in a single line.
function leftRotation(arr, d) {
return [ ...arr.slice(d), ...arr.slice(0, d) ];
}
console.log(leftRotation([1, 2, 3, 4, 5], 2));
Don't rotate N number of times. Shift N % (length of array) times, because Let's say you have an array of 5 items and you are asked to shift it 5 times then you essentially do not have to shift even once.
Start : [1, 2, 3, 4, 5]
1: [2, 3, 4, 5, 1]
2: [3, 4, 5, 1, 2]
3: [4, 5, 1, 2, 3]
4: [5, 1, 2, 3, 4]
5: [1, 2, 3, 4, 5]
EDIT:
You could use similar logic to optimize the code instead of actually shifting elements in the array. For example: In case of N = 73000, D = 60000, you could splice the array by 73000 % 60000 and then just append the returned spliced array to the existing array and return it.
For an array arr a method shift() can have a time complexity of O(arr.length).
If d is larger than n then you still perform shift() d times.
In total, your time complexity can rise to O(d * arr.length) that is definitely too long.
However, this problem can be solved in O(arr.length) time and space. If you know d then you can shift each item by d positions to the left easily. For instance, arr.length = 5 and d = 2
position: 0 1 2 3 4
arr: 4 3 5 1 6
position in arr: 2 3 4 0 1
shifted_arr: 5 1 6 4 3
So actually, each item at position i in the shifted array corresponds to an item at position (i + d) % arr.length in the original array arr. Hence, the code can look as follows:
function leftShift(arr, d) {
let newArr = [];
let size = arr.length;
for (var i = 0; i < size; i++) {
newArr.push(arr[(i + d) % size]);
}
return newArr;
}
console.log(leftShift([4, 3, 5, 1, 6], 2))