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

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

Related

JavaScript algorithm: is there a way to sort an already sorted array with the absolute values of its elements

I got this question during an interview.
I have an array that contains both negative and positive integers that are already sorted e.g.
const array = [-5, -3, 0, 2,7]
I am trying to write a function to sort the array using the absolute values of its elements. So the sorted array would be [ 0, 2, 3, 5, 7 ]
Here is my attempt
function sortArrayWithAbsoluteValue(array) {
const result = array.map(num => Math.abs(num)).sort((a,b) => a - b)
return result
}
Apparently, this works but it doesn't take advantage of the fact that the array is already sorted . Is there a better or more clever/efficient way to sort this?
the easiest solution is to introduce a new array and simply unshift it with elements from the first array
const array = [-9, -8, -5, -3, -2, 0, 2,7];
const newArray = [];
let i = 0, j = array.length - 1;
while(i <= j) {
const first = Math.abs(array[i]);
const last = Math.abs(array[j]);
if(first > last){
newArray.unshift(first)
i++;
}
else {
newArray.unshift(last)
j--;
}
}
console.log(newArray)
But this solution could be challenged by interviewers as unshift operator is slow o(n) so we can create newArray with the same size as array and then simply fill it in a similar way
const array = [-9, -8, -5, -3, -2, 0, 2,7];
const newArray = new Array(array.length);
let i = 0, j = array.length - 1, l = array.length - 1;
while(i <= j) {
const first = Math.abs(array[i]);
const last = Math.abs(array[j]);
if(first > last){
newArray[l] = first;
i++;
}
else {
newArray[l] = last;
j--;
}
l--;
}
console.log(newArray)
hope it helps!
You can let two indexes move towards eachother from either ends of the input array and based on how they compare, you copy the absolute value to the target array, filling it from end to front:
function absSorted(array) {
let result = Array(array.length);
for (let k = array.length - 1, i = 0, j = k; k >= 0; k--) {
result[k] = Math.abs(array[-array[i] < array[j] ? j-- : i++]);
}
return result;
}
const array = [-5, -3, 0, 2, 7];
console.log(absSorted(array));
You can use two iterators. One iterator starts from left and the other from right. Since the array is sorted one iterator points to the max absolute value. Store this value in a new array and iterate that iterator
const array = [-5, -3, 0, 2,7]
function f(array) {
let i = 0;
let j = array.length - 1;
const newArray = [];
while (i <= j) {
if (Math.abs(array[i]) < Math.abs(array[j])) {
newArray.push(Math.abs(array[j]));
--j;
} else {
newArray.push(Math.abs(array[i]));
++i;
}
}
return newArray;
}
console.log(f(array));
You can start at the min values with the inverted logic to get an increasing sort:
const array = [-5, -3, 0, 2, 7]
function g(array) {
let j = 0;
while (j < array.length && array[j] < 0) {
++j;
}
let i = j - 1;
const newArray = [];
while (i >= 0 && j < array.length) {
if (Math.abs(array[i]) < Math.abs(array[j])) {
newArray.push(Math.abs(array[i]));
--i;
} else {
newArray.push(Math.abs(array[j]));
++j;
}
}
if (i >= 0) {
newArray.push(...array.slice(0, i + 1).reverse().map(el => -el));
}
if (j < array.length) {
newArray.push(...array.slice(j));
}
return newArray;
}
console.log(g(array));
I converted all the numbers to the absolute value first using map
Then using a while loop, I used the indexOf and Math.min functions and the spread operator (...) to find the index of the minimum number of the array
Then I removed that from the array using splice
const array = [-5, -3, 0, 2,7];
function resort(array) {
const newArray = [];
array = array.map(i => Math.abs(i));
while (array.length) {
const minIndex = array.indexOf(Math.min(...array));
newArray.push(array.splice(minIndex, 1)[0]);
}
return newArray;
}
console.log(resort(array));

Why does my javascript's form loop return NAN while adding array

I am trying to add all array elements with basic for loop for some reason, my variable 'result' return NaN.
let array = [1, 2, 3, 4, 5];
let result = 0;
const arraySum = (arr) => {
for (let i = 0; i <= arr.length; i++) {
result = arr[i] + result
}
console.log(result)
}
arraySum(array)
Please use basic looping to answer, I tried .reduce method but want to use basic loops
Thank you
Your condition of i <= arr.length should be using i < arr.length
The length of the array is 5 but the index of the last number is 4, so you don't want <= there.
let array = [1, 2, 3, 4, 5];
let result = 0;
const arraySum = (arr) => {
for (let i = 0; i < arr.length; i++) {
result = arr[i] + result
}
console.log(result)
}
arraySum(array)
Length start at 1, so you need to set < operator in your loop :
let array = [1, 2, 3, 4, 5];
let result = 0;
const arraySum = (arr) => {
for (let i = 0; i < arr.length; i++) {
result = arr[i] + result
console.log(result)
}
console.log("result = ", result)
}
arraySum(array)
The reason for this problem is that the array has a length of 5 and the last index is 4. When the loop is at index = 5 there is no element at position 5. The result will therefore be undefined. To avoid this problem, the for loop should be like this:
for (let i = 0; i < arr.length; i++)
or
for(const i in arr)
You put '<=' in the for loop but you must use just '<'.
if array = [1,2,3] then length = 3 but array index goes from 0 to 2 not 3
you could try, if simple enough:
let array = [1, 2, 3, 4, 5];
let result = 0;
arraySum = (arr) => {
for (let i = 0; i < arr.length; i++) {
result += arr[i]
}
console.log(result)
}
arraySum(array)
the "<=" shoud be placed by "<"
let array = [1, 2, 3, 4, 5];
let result = 0;
const arraySum = (arr) => {
for (let i = 0; i <= array.length; i++) {
result += array[i];
}
console.log(result);
};
arraySum(array);

JS: restart loop with a updated index number

Is there a possibility to restart this loop with a new index number:
let ar = [1, 1, 2, 1, 2, 1, 3, 2, 3, 1];
let sortedArray = ar.sort();
let sameNumbersArray = [];
let numberOfSameNumbers = 0;
let lastIndexNumber = 0;
for (i = lastIndexNumber; i < sortedArray.length; i++) {
if (sortedArray[i] == sortedArray[i + 1]) {
const sameNumber = sortedArray[i];
sameNumbersArray.push(sameNumber);
} else {
break;
}
let lastIndexFromNumberArray = [];
lastIndexFromNumberArray.push(sameNumbersArray.length);
lastIndexFromNumberArray.push(3);
lastIndexFromNumberArray.push(2);
lastIndexNumber = lastIndexFromNumberArray.reduce(function (a, b) {
return a + b;
}, 0);
So basically that the loop (lastIndexNumber) starts with index[0], but then restarts with index[5] and index[7].
How would one add this extra loop?
I'm not 100% clear on the aim here. Are you able to elaborate on the desired result of the above?
It looks like you want to get an array of the unique numbers and perhaps the number of unique numbers from the source array?
If so, here's another way which might be cleaner:
let ar = [1, 1, 2, 1, 2, 1, 3, 2, 3, 1];
let sortedArray = ar.sort();
let newSameNumbersArray = unique(sortedArray);
//array of unique numbers:
console.log(newSameNumbersArray);
//count of unique numbers:
console.log(newSameNumbersArray.length);
function unique(array) {
return Array.from(new Set(array));
}
This is based on this answer: https://stackoverflow.com/a/44405494/4801692
That said, you can directly set the value of i and use continue to move to the 'next' iteration.
i = 5;
continue;
This is bad though as you are in danger of feeding i a lower number and getting stuck in an infinite loop. If you can explain the requirement a little more I might be able to suggest something better.
you can do such thing to find the pairs
let ar = [10, 10, 10, 20, 20, 10 ,30, 20 ,30]
function findPair(ar) {
let counts = {};
let count = [];
let sum = 0;
for(let i = 0; i < ar.length; i++){
let item = ar[i]
counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
}
count = Object.values(counts);
for(let i = 0; i < count.length; i++){
if(count[i] >= 2){
sum += Math.floor(count[i]/2)
}
}
console.log(sum)
}
findPair(ar)

Javascript Counting Sort implementation

Is this a good way or the best way to implement Counting Sort in Javascript?
Can't find a standard JS Counting Sort example.
function countingSort(arr){
var helper = []; // This helper will note how many times each number appeared in the arr
// Since JS arrary is an object and elements are not continuously stored, helper's Space Complexity minor that n
for(var i = 0; i<arr.length; i++){
if(!helper[arr[i]]){
helper[arr[i]] = 1;
}else{
helper[arr[i]] += 1;
}
}
var newArr = [];
for(i in helper){
while(helper[i]>0){
newArr.push(parseInt(i));
helper[i]--;
}
}
return newArr;
}
var arr = [5,4,3,2,1,0];
console.log(countingSort(arr)); // [0, 1, 2, 3, 4, 5]
The code is correct, with some comments:
In general, the use of for..in on arrays is discouraged, but unless you define enumerable properties on the Array prototype (which is a bad idea anyway), your use of it is fine to me
You could improve the part where you loop to push the same value several times. This can be done in "one" go by concatenating Array(helper[i]).fill(i) to the results.
You could also use reduce to make the function more functional programming style. In the extreme, it could look like this:
function countingSort(arr){
return arr.reduce( (acc, v) => (acc[v] = (acc[v] || 0) + 1, acc), [] )
.reduce( (acc, n, i) => acc.concat(Array(n).fill(i)), [] );
}
// Sample run:
var arr = [5,4,3,2,1,0];
console.log(countingSort(arr)); // [0, 1, 2, 3, 4, 5]
counting sort is to start by initializing an auxiliary array of length k, that will hold the count of each number. Each index has an initial value of 0. After that, you loop through the input array and increase the “count” for each value by 1 every time you encounter that number in the array. Now, the auxiliary array holds the number of times each element is in the input array. The last step is to loop from the minimum value to the maximum value. In this loop, you’ll loop through each corresponding value in the count array, and add the elements who’s count is greater than 0 to the array in sequential order. You add each item by using a secondary incrementing variable (e.g. if we’re using “i” to loop from the min to max values, then we’ll use “j” to loop through the array), then increasing that second incrementing variable so the next item is placed in the next highest array index, and finally you decrease the value of the current item in the count array so that you don’t add too many of elements that value.
const countingSort = (arr, min, max) => {
const count = {};
// First populate the count object
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]] += 1;
}
/* Now, count is indexed by numbers, with values corresponding to occurrences, eg:
* {
* 3: 1,
* 4: 0,
* 5: 2,
* 6: 1,
* 7: 0,
* 8: 0,
* 9: 1
* }
*/
// Then, iterate over count's properties from min to max:
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
};
console.log(countingSort([3, 6, 5, 5, 9], 3, 9));
const countingSort = (arr, min, max) => {
let counters = [...Array(max+1)].map(e => 0);
let result = []
for(let i = min; i < max; i++){
counters[arr[i]] += 1
}
for(let j = min; j <= max; j++){
while( counters[j] > 0){
result.push(j)
counters[j]--
}
}
return result
}
const countingSort = (arr, min, max) => {
const count = {};
// First populate the count object
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]] += 1;
}
/* Now, count is indexed by numbers, with values corresponding to occurrences, eg:
* {
* 3: 1,
* 4: 0,
* 5: 2,
* 6: 1,
* 7: 0,
* 8: 0,
* 9: 1
* }
*/
// Then, iterate over count's properties from min to max:
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
};
console.log(countingSort([3, 6, 5, 5, 9], 3, 9));
const countingSort = (arr, min, max) => {
const count = {};
// First populate the count object
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]] += 1;
}
/* Now, count is indexed by numbers, with values corresponding to occurrences, eg:
* {
* 3: 1,
* 4: 0,
* 5: 2,
* 6: 1,
* 7: 0,
* 8: 0,
* 9: 1
* }
*/
// Then, iterate over count's properties from min to max:
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
};
console.log(countingSort([3, 6, 5, 5, 9], 3, 9));
let a = [2, 1, 1, 0, 2, 5, 4, 0, 2, 8, 7, 7, 9, 2, 0, 1, 9];
let max = Math.max(...a);
let min = Math.min(...a);
function countingSort(arr) {
const count = [];
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]]++;
}
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
}
console.log(countingSort(a));
The simplest way to solve this problem you write like this:
const range = (start, stop, step) => {
if (typeof stop == "undefined") {
stop = start;
start = 0;
}
if (typeof step == "undefined") step = 1;
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) return [];
let result = [];
for (let i = start; step > 0 ? i < stop : i > stop; i += step)
result.push(i);
return result;
};
const numbers = [1, 2, 2, 2, 1, 3, 3, 1, 2, 4, 5];
const max = Math.max.apply(Math, numbers);
let count = Array.apply(null, Array(max + 1)).map(() => 0);
for (x of numbers)
count[x] += 1;
let arr = [];
for (x in range(max + 1))
for (i in range(count[x]))
arr.push(parseInt([x]));
console.log(arr);

Sort an array containing numbers using a 'for' loop

I am new to JavaScript, and I have an array which contains numbers.
var arr = [2,4,8,1,5,9,3,7,6];
How can I sort it using a native for loop in JavaScript?
I know sort function is available, but I want it through for loop.
The output should be:
var res = [1,2,3,4,5,6,7,8,9];
var Arr = [1, 7, 2, 8, 3, 4, 5, 0, 9];
for (var i = 1; i < Arr.length; i++)
for (var j = 0; j < i; j++)
if (Arr[i] < Arr[j]) {
var x = Arr[i];
Arr[i] = Arr[j];
Arr[j] = x;
}
console.log(Arr);
I would do something like this...
var input = [2,3,8,1,4,5,9,7,6];
var output = [];
var inserted;
for (var i = 0, ii = input.length ; i < ii ; i++){
inserted = false;
for (var j = 0, jj = output.length ; j < jj ; j++){
if (input[i] < output[j]){
inserted = true;
output.splice(j, 0, input[i]);
break;
}
}
if (!inserted)
output.push(input[i])
}
console.log(output);
Maybe there are more efficient ways, but if you want to use the for loop, it's my first idea...
First create an empty array where the sorted numbers will be pushed into.
let sorted = [];
Secondly, create a very large amount of numbers that none of the numbers of the array can match. This number will be used for the very first comparison to determine which number of the array is smaller.
let comparison = 9000000000;
Create a for loop.
This loop will have another loop inside of it. The inner loop will check for the smallest number in a given array, and once the smallest number is gotten, it will be push into the empty array we created. The smallest number will also be removed from the initial array and then the array will run again.
for(a = 0; a < arr.length; a++){
//This inner loop fetches the smallest number.
for(b = 0; b < arr.length; a++){
if(comparison > arr[b]){
comparison = arr[b];
}
}
// The smallest number is assigned to comparison
// Now it being pushed to the empty array
sorted.push(comparison);
// Remove the smallest number from the initial array
let indexOfSmallNumber = arr.indexOf(comparison);
arr.splice(indexOfSmallNumber, 1);
// Set the comparison back to 9000000000;
comparison = 90000000000;
a = -1;
// Here, "a" is our main loop index counter and we are
// setting it to -1 because we don't want it to change
// to 2 by default, doing this will make the loop run
// forever until the initial array is empty.
}
let arr = [4, 2, 5, 1]
let temp;
function converter(arr) {
for(let i=0; i<arr.length; i++) {
for (let j=i+1; j<arr.length; j++) {
if(arr[i] > arr[j]) {
temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
}
return arr
}
const newArr = converter(arr)
console.log(newArr)
Use:
let s = [4, 6, 3, 1, 2];
for (let i = 0; i < s.length;) {
if (s[i] > s[i + 1]) {
let a = s[i];
s[i] = s[i + 1];
s[i + 1] = a;
i--;
}
else {
i++;
}
}
This is a sorting algorithm which has a best time complexity of O(n) and the worst time of O(n^2).
This code checks for each number, and then compares to all numbers on the left side.
To check the time it takes each code to run, you can also use this code below:
let start = process.hrtime.bigint()
let end = process.hrtime.bigint()
console.log(end - start) // This measures the time used in nano seconds.
Also for microseconds, you can use this performance.now().
Here there is a very simple solution that uses a temporary array to store the values greater than the current one. Then it puts the current value between the lesser and the greater values:
var arr = [2,4,8,1,5,9,3,7,6];
var res = [];
for (const c of arr) {
let tmp = [];
while (c < res[res.length-1]) {
tmp.unshift(res.pop());
}
res = [...res, c, ...tmp];
}
const numberArr = [5, 9, 2, 8, 4, 10, 1, 3, 7, 6];
function sortedFunction(arr) {
let sortedArr = [];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
let n = 0;
if (arr[i] > arr[j]) {
n = arr[i];
arr[i] = arr[j];
arr[j] = n;
}
}
sortedArr.push(arr[i]);
}
return sortedArr;
}
sortedFunction(numberArr);
Under the JavaScript array sort section of W3Schools it talks about how to compare a value in an array with the others and then order them based on the values being returned. I updated the code to use a for loop to sort values.
// Ascending points
var points = [5.0, 3.7, 1.0, 2.9, 3.4, 4.5];
var output = [];
var i;
for (i = 0; i < points.length; i++) {
points.sort(function (a, b) {
return a - b
});
output += points[i] + "<br>";
}
console.log(output);
// Descending points
var points = [5.0, 3.7, 1.0, 2.9, 3.4, 4.5];
var output = [];
var i;
for (i = 0; i < points.length; i++) {
points.sort(function (a, b) {
return b - a
});
output += points[i] + "<br>";
}
console.log(output);
const array = [12, 3, 45, 61, 23, 45, 6, 7];
function sortArray(array) {
for (var i = 0; i < array.length; ++i) {
for (var j = 0; j < array.length - 1 - i; ++j) {
if (array[j] > array[j + 1]) {
[array[j], array[j + 1]] = [array[j + 1], array[j]];
}
}
}
return array;
}
console.log(sortArray(array));
Here are the two solutions for the same algorithm:
Solution 1:
We can directly use JavaScript functions:
let arr = [2, 4, 8, 1, 5, 9, 3, 7, 6]
const changeOrder = (arr) => {
return arr.sort((a, b) => a - b)
}
let result = changeOrder(arr);
console.log(result) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Solution 2:
We can use a JavaScript for loop for doing the same
let arr = [2, 4, 8, 1, 5, 9, 3, 7, 6]
const changeOrder = (arr) => {
for(let i=1; i< arr.length; i++) {
for(let j=0; j < i; j++) {
if(arr[i] < arr[j]) {
let x = arr[i]
arr[i] = arr[j]
arr[j] = x
}
}
}
return arr;
}
let result = changeOrder(arr);
console.log(result) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
An improvement to previous answer
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}

Categories