Splitting array into equal halves - javascript

Problem: find an index N where the sum of the integers to the left of N is equal to the sum of the integers to the right of N. If there is no index that would make this happen, return -1.
My solution
function findEvenIndex(arr) {
var sum = i => i.reduce((a, b) => a + b),
l = arr.length;
for (let j = 0; j <= l; j++) {
if (sum(arr.slice(0, j - 1)) === sum(arr.slice(j, l))) {
return j
} else {
continue;
}
}
return -1
}
console.log(
findEvenIndex([1, 2, 3, 4, 3, 2, 1])
)
When I run this on say findEvenIndex([1,2,3,4,3,2,1]), It doesn't return anything? Where is the error that prevents 3 from being returned in the case of this example?
I've set the for loop procedure as follows to see what's going on
for(let j = 0; j <= arr.length; j++){
var left = arr.slice(0, j-1), right = arr.slice(j)
console.log(left, right)
}
/* returns
[1] [3,4,3,2,1]
[1,2] [4,3,2,1]
[1,2,3] [3,2,1]
as expected
*/
However, when try to console.log the sum of these arrays:
function sum(i){ return i.reduce((a, b) => a+b)}
var l = arr.length;
for(let j = 0; j <= l; j++){
var left = arr.slice(0, j-1), right = arr.slice(j)
console.log(sum(left), sum(right))
}
Using the snippet above, findEvenIndex([1,2,3,4,3,2,1]) returns "15 16"?

The main issue with your code is that calling sum([]) throws an error (which you will find in the console during debugging):
Reduce of empty array with no initial value
The reduce method does not know what to return if your array doesn't have any values. You solve it by passing the initial value as a second argument to .reduce:
const add = (a, b) => a + b;
[1, 2, 3].reduce(add); // add(add(1, 2), 3)
[1, 2].reduce(add); // add(1, 2)
[1].reduce(add); // 1
[].reduce(add); // ERROR: Reduce of empty array
// with no initial value
[1, 2].reduce(add, 0); // add(add(0, 1), 2)
[1].reduce(add, 0); // add(0, 1)
[].reduce(add, 0); // 0
Once you fix that, it's easier to debug the rest of the code.
Fixing it
Here's an example that I think does what it should do:
function findEvenIndex(arr) {
// Add a seed value --v
var sum = i => i.reduce((a, b) => a + b, 0),
l = arr.length;
for (let j = 0; j <= l; j++) {
const left = arr.slice(0, j);
const right = arr.slice(j + 1);
const leftSum = sum(left);
const rightSum = sum(right);
console.log(
{ left, right, leftSum, rightSum }
);
if (leftSum === rightSum) {
return j
}
}
return -1
}
console.log(
findEvenIndex([1]), // 0
findEvenIndex([1, 2, 3, 4, 3, 2, 1]), // 3
findEvenIndex([10, 0, 5, 5]), // 1
findEvenIndex([3, 2, 1]) // -1
)
Another approach
Note that looping over all elements of the array for every index is quite expensive! A more efficient approach would be:
Take the sum of the source array, store it as rightSum
Define leftSum as 0
Look at the integer value at index 0 and subtract it from rightSum
If leftSum === rightSum, return 0
Else, add value to leftSum and increment index
Once you've reached the final index, return -1
const findEvenIndex = (arr) => {
let leftSum = 0;
let rightSum = arr
.reduce((a, b) => a + b, 0);
for (let i = 0; i < arr.length; i += 1) {
const n = arr[i];
rightSum -= n;
if (leftSum === rightSum) return i;
leftSum += n;
}
return -1;
}
console.log(
findEvenIndex([1]), // 0
findEvenIndex([1, 2, 3, 4, 3, 2, 1]), // 3
findEvenIndex([10, 0, 5, 5]), // 1
findEvenIndex([3, 2, 1]) // -1
)

You can get the index like following using reduce(). Your implementation regarding reduce() is not correct.
function findEvenIndex(arr)
{
for(let i = 0; i < arr.length; i++) {
let leftSum = arr.slice(0, i).reduce((accumulator, current) => accumulator + current, 0);
let rightSum = arr.slice(i + 1).reduce((accumulator, current) => accumulator + current, 0);
if (leftSum === rightSum) {
return i;
}
}
return -1;
}
console.log(
findEvenIndex([1, 2, 3, 4, 3, 2, 1])
)
Please check following blog to find out how Array reduce() work
https://www.javascripttutorial.net/javascript-array-reduce/

Upon finishing my solution, I noticed that it's effectively the same as #Abu's answer above. The idea is to brute force the way through the array, comparing the two halves as you go.
/*
Find an index N where the sum of the integers to the left of N is equal to the sum of the integers to the right of N. If there is no index that would make this happen, return -1
*/
const array = [10, 90, 10, 1, 10, 90, 10];
// incrementTotal :: (Number t, Number n) -> t
incrementTotal = (total, number) => total + number;
// indexIsEqual :: (Array a, Number c) -> Boolean
function indexIsEqual(array, count) {
let chunkL = array.slice(0, count-1);
let chunkR = array.slice(count , );
return chunkL.reduce(incrementTotal) === chunkR.reduce(incrementTotal);
}
// findEvenIndex :: (Array a) -> (a[x] || -1)
function findEvenIndex(array) {
for (let count = 2; count < array.length; count++) {
if (indexIsEqual(array, count)) {
return array[count-1];
}
}
return -1;
}
console.log(findEvenIndex(array));

Related

Given a list of n integers arr[0..(n-1)], determine the number of different pairs of elements within it which sum to k

I'm tackling this problem and I can't seem to arrive at the correct solution. The question is:
"Given a list of n integers arr[0..(n-1)], determine the number of different pairs of elements within it which sum to k. If an integer appears in the list multiple times, each copy is considered to be different; that is, two pairs are considered different if one pair includes at least one array index which the other doesn't, even if they include the same values.
My approach is that I'm building a map that contains each number in the array and the number of times it occurs. Then I iterate over the map to find my answer.
function numberOfWays(arr, k) {
let output = 0;
let map = {};
// put values and # of occurences into map
for(let i = 0; i < arr.length; i++) {
let key = arr[i];
if(!(key in map)) {
map[key] = 1;
} else {
map[key]++;
}
}
for(let key in map) {
let difference = k-key
if((difference) in map) {
if(k/2 === key) {
output += map[key]*(map[key]-1)/2;
} else {
output += map[key] * map[key] / 2; // divide by 2 so that pairs aren't counted twice
}
}
}
return output;
}
The two test cases are:
var arr_1 = [1, 2, 3, 4, 3]; expected result: [2] -- I'm getting [3]
var arr_2 = [1, 5, 3, 3, 3]; expected result: [4] -- I'm getting [5.5]
I'm definitely doing something wrong in my calculations, but I can't seem to wrap my ahead around it.
This is one way to nest the loops to find the pairs in array "arr" with the sum "k".
function numberOfWays(arr, k) {
let output = 0;
for (i = 0; i < arr.length; i++) {
for (n = i+1; n < arr.length; n++) {
if (arr[i] + arr[n] == k)
output++;
}
}
return output;
}
You could count the smaller and greater values for building k and then taker either the product or if only two of the same value is building the sum take factorial of the cound divided by two.
function numberOfWays(array, k) {
const
f = n => +!n || n * f(n - 1),
pairs = {};
for (const value of array) {
const smaller = Math.min(value, k - value);
pairs[smaller] ??= { one: 2 * smaller === k, min: 0, max: 0 };
pairs[smaller][value === smaller ? 'min' : 'max']++;
}
let count = 0;
for (const k in pairs) {
const { one, min, max } = pairs[k];
if (one) {
if (min > 1) count += f(min) / 2;
} else if (min && max) {
count += min * max;
}
}
return count;
}
console.log(numberOfWays([1, 2, 3, 4, 3], 6)); // 2
console.log(numberOfWays([1, 5, 3, 3, 3], 6)); // 4
function numberOfWays(items, k) {
// Clone as to not mutate original array
const arr = [...items]
let count = 0
// Stop comparing when no items left to compare
while (arr.length) {
for (let i = 0; i < arr.length; i++) {
// Compare each item to the first item
const sum = arr[0] + arr[i + 1]
if (sum === k) {
count++
}
}
// Remove the first item after comparing to the others
arr.shift()
}
return count
}
console.log(numberOfWays([1, 2, 3, 4, 3], 6))
console.log(numberOfWays([1, 5, 3, 3, 3], 6))
console.log(numberOfWays([1, 1, 1, 1, 1], 2))
import math
from math import factorial as f
def get_number_of_combination(n,r):
return f(n)//(f(n-r)*f(r))
def numberOfWays(arr, k):
num_count = {}
num_ways = 0
for i in arr:
old_count = num_count.get(i,0)
num_count.update({i: old_count+1})
for i in list(num_count.keys()):
if i == k - i and num_count.get(i,0) > 1:
num_ways += (get_number_of_combination(num_count.get(i,0),2))
num_count.update({i:0})
else:
i_n = num_count.get(i, 0)
ki_n = num_count.get(k-i, 0)
num_ways += i_n * ki_n
num_count.update({i:0,k-i:0})
return num_ways

Splitting of array

Given a non-empty array, if there is a place to split the array so that the sum of the numbers on one side is equal to the sum of the numbers on the other side return the length of the two arrays as an array but if there is no place to split the array, return -1
canBalance([1, 1, 1, 2, 1]) → [3,2]
canBalance([2, 1, 1, 2, 1]) → -1
canBalance([10, 10]) → [1,1]
function canBalance(array) {
//Type your solutions here
}
module.exports = canBalance;
Make two variables, and add and subtract each item in the array until they are equal.
function canBalance(array) {
let start = 0, end = array.reduce((a, c) => a + c, 0);
for (let i = 0; i < array.length; i++) {
start += array[i];
end -= array[i];
if (start == end) {
return [i + 1, array.length - (i + 1)];
}
}
return -1;
}
console.log(canBalance([1, 1, 1, 2, 1]));
console.log(canBalance([2, 1, 1, 2, 1]));
console.log(canBalance([10, 10]));
loop through the array from the first (index 0) to the one before the last (length -1) since you want to check only until the second last to compare against the last one.
you can use slice to get the array minus the one element being iterated each time and use a reducer to get the sum
const reducer = (a, c) => a+c;
function canBalance(array) {
var result = [];
var arr = [];
for(var i=0; i<array.length - 1; i++){
arr.push(array[i]);
var leftover = array.slice(i+1,array.length);
if(arr.reduce(reducer) === leftover.reduce(reducer)){
result.push(arr.length);
result.push(leftover.length);
}
}
return result.length > 0 ? result : -1;
}

Avoid using nested loops to find the max-sized sub-string of an array?

Added maximum number according to the input length should be returned.
For example, if the length is 2 then the max among arr[0] + arr[1], arr[1] + arr[2], arr[2] + arr[3] should be returned.
Input is array and length.
I solved this in a real job interview but I think there will be a way not to use nested loop.
const add = (arr, len) => {
let rtnVal = 0
for (let i = len - 1; i < arr.length; i++) {
let temp_idx = i;
let temp_sum = 0;
for (let j = 0; j < len; j++) {
temp_sum = (temp_sum || 0) + arr[temp_idx]
temp_idx -= 1
}
if (temp_sum > rtnVal) {
rtnVal = temp_sum
}
}
return rtnVal
}
console.log(add([1, 2, 3, 4, 5, 6, 7, 8, 9], 4))
I expect the output 30
// enhanced nested loop
const add = (arr, len) => {
let rtnVal = 0;
for(let i=len-1;i<arr.length;i++){
let sum = 0
for(let j=i;j>=i-len+1;j--){
sum += arr[j]
}
if (sum > rtnVal) rtnVal = sum
}
return rtnVal
}
console.log(add([9, 9, 9, 4, 5, 6, 7, 8, 9], 3))
Use a moving window. Add up len numbers starting at the beginning. Then continue through the array adding the next number and subtracting the trailing number.
const add = (arr, len) => {
return arr.reduce((a,v,i,arr) => {
a.running += v;
if(i >= len) {
a.running -= arr[i-len];
}
if(i+1 >= len && a.largest < a.running) {
a.largest = a.running;
}
return a;
}, {
largest: Number.NEGATIVE_INFINITY,
running: 0
}).largest;
}
console.log(add([1,2,3,4,5,6,7,8,9],4)); // 30
console.log(add([-1,-1,-1,-1],2)); // -2
console.log(add([1],1)); // 1
Assuming its sorted like your example. You can use negative slice to select from end and then reduce the array.
const add = (arr, len) => arr.slice(len > arr.len ? arr.len : -len).reduce((total, num) => total + num)
console.log(add([1, 2, 3, 4, 5, 6, 7, 8, 9], 4))

Why my Move Zeroes function is wrong answer in leetcode?

I was doing Move Zeroes in leetcode.
I write a function to solve but leetcode said it's a wrong answer.
Could someone see what is wrong in my code?
Requirement:the original array must be mutated
Input:[0,1,0,3,12]
Output:[1,3,12,0,0]
Input:[2,1]
Output:[1,2]
Here is my JS:
var moveZeroes = function(nums) {
var ZeroArray=[]
for(let i=0;i<nums.length;i++){
if(nums[i]===0){
ZeroArray.push(nums[i])
nums.splice(i,1);
}
}
nums.sort((a,b)=>(a-b))
for(let j=0;j<ZeroArray.length;j++){
nums.push(ZeroArray[j])
}
return nums;
};
console.log(moveZeroes([0,1,0,3,12])); //Should return [ 1,3,12,0,0]
console.log(moveZeroes([2,1]));//Should return [1,2]
Your
nums.shift(nums[i]);
will remove (and discard) whatever exists at the 0th index in nums at the time. It would probably be easier to push to a different array if the num is not 0, then combine the arrays at the end (no sorting):
var moveZeroes = function(nums) {
var ZeroArray = []
var nonZeroArray = [];
for (let i = 0; i < nums.length; i++) {
if (nums[i] === 0) {
ZeroArray.push(nums[i])
} else {
nonZeroArray.push(nums[i]);
}
}
return [...nonZeroArray, ...ZeroArray];
};
console.log(moveZeroes([0, 1, 0, 3, 12])) //Should return [ 1,3,12,0,0]
Or, if you do want to .sort, .sort only:
var moveZeroes = function(nums) {
nums.sort((a, b) => (a === 0) - (b === 0));
return nums;
};
console.log(moveZeroes([0, 1, 0, 3, 12])) //Should return [ 1,3,12,0,0]
Do check === 0 - otherwise, your
.sort((a,b)=>(a-b))
will put negative numbers after the 0s, when you want 0s to come at the end regardless.
If you also need to preserve the original order of non-zeros, iterate over the array, splice out 0s while keeping track of how many you remove, then push them at the end:
var moveZeroes = function(nums) {
let count = 0;
for (let i = nums.length - 1; i >= 0; i--) {
if (nums[i] === 0) {
nums.splice(i, 1);
count++;
}
}
nums.push(...new Array(count).fill(0));
return nums;
};
console.log(moveZeroes([0, 1, 0, 3, 12])) //Should return [ 1,3,12,0,0]
Array.shift() removes the first element from an array, you most likely want to use Array.splice(i, 1)
Use filter to filter all the non zero elements and then append remaining array size with zeros.
let arr = [0,1,0,3,12];
let filtered = arr.filter(item => item !== 0);
let result = [...filtered, ...(new Array(arr.length - filtered.length).fill(0))]
console.log(result);
Using splice remove zero and count the spiced values. In a loop push the zeroes in the array equal to the count
var a=[0,1,0,3,12];
var count=0;
a.forEach(e=>{
if(e==0){
a.splice(a.indexOf(e),1)
count++
}})
for(var i=0;i<count;i++)
a.push(0)
console.log(a)
You could take a single loop approach with an additonal variable for the next index for swapping the values.
This approach works in situ, as the specs requires.
/**
* #param {number[]} nums
* #return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
var i, j = 0;
for (i = 0; i < nums.length; i++) {
console.log(...nums); // look!
if (nums[i] !== 0) { // check
[nums[j], nums[i]] = [nums[i], nums[j]]; // swap items
j++; // increment target
}
}
},
array = [0, 1, 0, 3, 12];
moveZeroes(array)
console.log(...array); // [1, 3, 12, 0, 0]
here is code to remove zeros in c++
void pushZerosToEnd(int arr[], int n)
{
int count = 0;
for (int i = 0; i < n; i++)
if (arr[i] != 0)
arr[count++] = arr[i];
while (count < n)
arr[count++] = 0;
}
int main()
{
int arr[] = {1, 9, 8, 4, 0, 0, 2, 7, 0, 6, 0, 9};
int n = sizeof(arr) / sizeof(arr[0]);
pushZerosToEnd(arr, n);
cout << "Array after pushing all zeros to end of array :n";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
var a = [1, 2, 0, 0, 3, 0, 3, 0, 2, 0, 0, 0, 5, 0];
function moveZero(b) {
for (var i = b.length - 1; i >= 0; i--) {
if (b[i] === 0) {
b.splice(i, 1);
b.push(0);
}
}
return b;
}
console.log(moveZero(a));

Find Missing Numbers from Unsorted Array

I found this JavaScript algorithm excercise:
Question:
From a unsorted array of numbers 1 to 100 excluding one number, how will you find that number?
The solution the author gives is:
function missingNumber(arr) {
var n = arr.length + 1,
sum = 0,
expectedSum = n * (n + 1) / 2;
for (var i = 0, len = arr.length; i < len; i++) {
sum += arr[i];
}
return expectedSum - sum;
}
I wanted to try and make it so you can find multiple missing numbers.
My solution:
var someArr = [2, 5, 3, 1, 4, 7, 10, 15]
function findMissingNumbers(arr) {
var missingNumbersCount;
var missingNumbers = [];
arr.sort(function(a, b) {
return a - b;
})
for(var i = 0; i < arr.length; i++) {
if(arr[i+1] - arr[i] != 1 && arr[i+1] != undefined) {
missingNumbersCount = arr[i+1] - arr[i] - 1;
for(j = 1; j <= missingNumbersCount; j++) {
missingNumbers.push(arr[i] + j)
}
}
}
return missingNumbers
}
findMissingNumbers(someArr) // [6, 8, 9, 11, 12, 13, 14]
Is there a better way to do this? It has to be JavaScript, since that's what I'm practicing.
You could use a sparse array with 1-values at indexes that correspond to values in the input array. Then you could create yet another array with all numbers (with same length as the sparse array), and retain only those values that correspond to an index with a 1-value in the sparse array.
This will run in O(n) time:
function findMissingNumbers(arr) {
// Create sparse array with a 1 at each index equal to a value in the input.
var sparse = arr.reduce((sparse, i) => (sparse[i]=1,sparse), []);
// Create array 0..highest number, and retain only those values for which
// the sparse array has nothing at that index (and eliminate the 0 value).
return [...sparse.keys()].filter(i => i && !sparse[i]);
}
var someArr = [2, 5, 3, 1, 4, 7, 10, 15]
var result = findMissingNumbers(someArr);
console.log(result);
NB: this requires EcmaScript2015 support.
The simplest solution to this problem
miss = (arr) => {
let missArr=[];
let l = Math.max(...arr);
let startsWithZero = arr.indexOf(0) > -1 ? 0 : 1;
for(i = startsWithZero; i < l; i++) {
if(arr.indexOf(i) < 0) {
missArr.push(i);
}
}
return missArr;
}
miss([3,4,1,2,6,8,12]);
Something like this will do what you want.
var X = [2, 5, 3, 1, 4, 7, 10, 15]; // Array of numbers
var N = Array.from(Array(Math.max.apply(Math, X)).keys()); //Generate number array using the largest int from X
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;}); //Return the difference
};
console.log(N.diff(X));
Option 1:
1. create a binary array
2. iterate over input array and for each element mark binary array true.
3. iterate over binary array and find out numbers of false.
Time complexity = O(N)
Space complexity = N
Option 2:
Sort input array O(nLogn)
iterate over sorted array and identify missing number a[i+1]-a[i] > 0
O(n)
total time complexity = O(nlogn) + O(n)
I think the best way to do this without any iterations for a single missing number would be to just use the sum approach.
const arr=[1-100];
let total=n*(n+1)/2;
let totalarray=array.reduce((t,i)=>t+i);
console.log(total-totalarray);
You can try this:
let missingNum= (n) => {
return n
.sort((a, b) => a - b)
.reduce((r, v, i, a) =>
(l => r.concat(Array.from({ length: v - l - 1 }, _ => ++l)))(a[i - 1]),
[]
)
}
console.log(missingNum([1,2,3,4,10]));
Solution to find missing numbers from unsorted array or array containing duplicate values.
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
var array1 = [1, 3, 4, 7, 9];
var n = array1.length;
var totalElements = array1.max(); // Total count including missing numbers. Can use max
var d = new Uint8Array(totalElements)
for(let i=0; i<n; i++){
d[array1[i]-1] = 1;
}
var outputArray = [];
for(let i=0; i<totalElements; i++) {
if(d[i] == 0) {
outputArray.push(i+1)
}
}
console.log(outputArray.toString());
My solution uses the same logic as trincot's answer
The time complexity is O(n)
const check_miss = (n) => {
let temp = Array(Math.max(...n)).fill(0);
n.forEach((item) => (temp[item] = 1));
const missing_items = temp
.map((item, index) => (item === 0 ? index : -1))
.filter((item) => item !== -1);
console.log(missing_items);
};
n = [5, 4, 2, 1, 10, 20, 0];
check_miss(n);

Categories

Resources