Related
I want to write an algorithm to remove duplicates and sort an array with single loop in javascript. I want to do it with algorithms not declarative methods.
I can sort it with single loop but can't remove duplicates. I will be glad if someone help me.
Number of elements in array is 10^6, each element is equal to or greater than 0, less than 300
This is my sorting algorithm:
var a = [2, 7, 5, 1, 3, 2, 7];
for (let i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
let temp = a[i]
a[i] = a[i + 1]
a[i + 1] = temp
i = -1
}
}
console.log(a)
It's honorable that you was curious enough to try to find a solution, even after the interview. A good sign for a programmer.
I would use an object to keep track of any duplicates.
Also loop from the end, mostly because it feels right, not messing up the index.
Change position in a if current < previous
Else add to the object.
Check if object has previous index, or
Check if current is the same as previous (ex. 8, 8 at the end of the array)
then splice the previous index.
Added numberOfLoops just because it's fun to know.
var a = [2, 2, -1, 8, 5, 1, 3, 3, 13, 2, 8, 8];
var temp = {}; // 1
var result = [];
var current, previous;
var numberOfLoops = 0;
for (let i = a.length - 1; i > 0 ; i--) { // 2
current = a[i];
previous = a[i - 1];
numberOfLoops++; // 8
if (temp.hasOwnProperty(previous) || // 5
current == previous) { // 6
a.splice(i - 1, 1); // 7
// i++;
} else if (current < previous) { // 3
a[i - 1] = current;
a[i] = previous;
i += 2;
delete temp[current];
} else { // 4
temp[current] = current;
}
}
console.log({numberOfLoops}); // 23
console.log(a); // [-1, 1, 2, 3, 5, 8, 13]
I did this module on functions and execution context - all questions have gone well but there is one challenge I have spent a lot of time on and still can't figure it out. Any help will be greatly appreciated. Thank you
Challenge question says:
Write a function addingAllTheWeirdStuff which adds the sum of all the odd numbers in array2 to each element under 10 in array1.
Similarly, addingAllTheWeirdStuff should also add the sum of all the even numbers in array2 to those elements over 10 in array1.
BONUS: If any element in array2 is greater than 20, add 1 to every element in array1.
// Uncomment these to check your work!
// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5])); // expected log [10, 12, 14, 23, 21]
// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22])); // expected log [11, 13, 15, 46, 44, 11]
// my attempt so far:
function addingAllTheWeirdStuff(array1, array2) {
// ADD CODE HERE
let result = []
for (let i = 0; i < array2.length; i++) {
if (array2[i] > 20) {
result = array1[i] += 1
}
}
for (let i = 0; i < array2.length; i++) {
if (array2[i] % 2 === 0 && array1[i] > 10) {
result = array1[i] + array2[i]
}
}
for (let i = 0; i < array2.length; i++) {
if (array2[i] % 2 !== 0 && array1[i] < 10) {
result = array1[i] + array2[i]
}
}
return result
}
You can easily achieve this using reduce and map array method, with the ternary operator:
const array1 = [1, 3, 5, 17, 15];
const array2 = [1, 2, 3, 4, 5];
function addingAllTheWeirdStuff(array1, array2) {
const oddSum = array2.reduce((sum, current) => current % 2 ? current + sum : 0 + sum, 0)
const oddEven = array2.reduce((sum, current) => current % 2 == 0 ? current + sum : 0 + sum, 0)
return array1.map(num => num < 10 ? num + oddSum : num + oddEven)
}
console.log(addingAllTheWeirdStuff(array1, array2))
If you break the challenge into smaller pieces, you can deconstruct it better and come up with your solutions.
This is what I did... I will be adding more comments shortly with more explanations
I chose to keep using loops as I assumed this was the point of the challenges (to practice for loops, multiple conditions, etc) - In other words, I chose to not use map / reduce on purpose but if that's allowed, use the answer by #charmful0x as it results in less code :)
// function to get sum of all odd numbers in array
function getSumOfAllOddNumbersInArray( elementArray ){
var sumOfOddNumbers = 0;
for (let i = 0; i < elementArray.length; i++) {
// use remainder operator to find out if element is odd or not
if (elementArray[i] % 2 !== 0 ) {
sumOfOddNumbers += elementArray[i];
}
}
return sumOfOddNumbers;
}
// function to get sum of all EVEN numbers in array
function getSumOfAllEvenNumbersInArray( elementArray ){
var sumOfEvenNumbers = 0;
for (let i = 0; i < elementArray.length; i++) {
// use remainder operator to find out if element is odd or not
if (elementArray[i] % 2 === 0 ) {
sumOfEvenNumbers += elementArray[i];
}
}
return sumOfEvenNumbers;
}
// Return true if there is at least one element in array that is greater than 20
function hasElementOverTwenty( elementArray ){
for (let i = 0; i < elementArray.length; i++) {
if (elementArray[i] > 20 ) {
// no need to keep looping, we found one - exit function
return true;
}
}
return false;
}
function addingAllTheWeirdStuff( firstArray, secondArray ){
var sumOfOddNumbersInArray = getSumOfAllOddNumbersInArray( secondArray );
var sumOfEvenNumbersInArray = getSumOfAllEvenNumbersInArray( secondArray );
var needToAddOne = hasElementOverTwenty( secondArray );
for (let i = 0; i < firstArray.length; i++) {
// Challenge One
if (firstArray[i] < 10) {
firstArray[i] = firstArray[i] + sumOfOddNumbersInArray;
} else if (firstArray[i] > 10) {
// Challenge Two
firstArray[i] = firstArray[i] + sumOfEvenNumbersInArray;
}
// bonus
if( needToAddOne ){
firstArray[i]++;
}
}
return firstArray;
}
// Uncomment these to check your work!
console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5]));
console.log('expected:' + [10, 12, 14, 23, 21] );
console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22]));
console.log('expected:' + [11, 13, 15, 46, 44, 11] );
Challenge question says: Write a function addingAllTheWeirdStuff which adds the sum of all the odd numbers in array2 to each element under 10 in array1.
Similarly, addingAllTheWeirdStuff should also add the sum of all the even numbers in array2 to those elements over 10 in array1.
BONUS: If any element in array2 is greater than 20, add 1 to every element in array1.
The following code seems to be unable to find the number in the list. Why might this be?
Trying this with the number to search for as '9' and the array of numbers consisting of numbers between 1-10 inclusively.
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
count = 0;
function binarySearch(array, number) {
mid = Math.floor(array.length / 2);
if (number === array[mid]) {
return count;
}
else if (number < array[mid] && array.length > 1) {
count++;
arrayFirst = array.splice(0, array[mid]);
console.log("Tried: ", array[mid])
console.log(arrayFirst);
return binarySearch(arrayFirst, number);
}
else if (number > array[mid] && array.length > 1) {
count++;
arraySecond = array.splice(array[mid], array.length);
console.log("Tried: ", array[mid])
console.log(arraySecond);
return binarySearch(arraySecond, number);
}
else {
return 'number doesnt exist';
}
}
console.log(binarySearch(array, 4));
The code is now struggling with finding the number 10
New Edit:
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13,14,15,16,17,18,19,20];
count = 0;
function binarySearch(array, number) {
mid = Math.floor(array.length/ 2);
if (number === array[mid]) {
return count;
}
else if (number < array[mid] && array.length > 1) {
count++;
arrayFirst = array.splice(0, mid);
console.log("Tried: ", array[mid])
console.log(arrayFirst);
return binarySearch(arrayFirst, number);
}
else if (number > array[mid] && array.length > 1) {
count++;
arraySecond = array.splice(array[mid], mid);
console.log("Tried: ", array[mid])
console.log(arraySecond);
return binarySearch(arraySecond, number);
}
else {
return 'number doesnt exist';
}
}
console.log(binarySearch(array, 10));
This:
array = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
is not an array, it's interpreted as a list of initialization, like this:
array = 1, x = 2, y = 3...;
and so your array is just 1, and not the entire list. Also keep in mind that it is Not Recommended to declare a variable without var keyword. It can accidently overwrite an existing global variable. Instead you should use var, let or const based on the use of that variable
Instead, this should be your array:
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Few pointers here:
Your condition includes an undefined variable arr. You've been using array.
Your array must be array = [1,2,3]
I would suggest to instantiate your variables arrayFirst, mid, arraySecond as const const mid = ... so they are block scoped and not global vars
Edit: Looks like you've modified your arr condition. Please avoid edits as it makes answers irrelevant.
You are using array.splice(0, array[mid])
array[mid] is the value in the array and you need the quantity of elements to subtract array.splice(0, mid) splice docs
also index start from 0 so your array[mid] is taking the 6th element and not the middle.
Some changes:
Take counting inside of the function by returning either one or zero or one plus the result of the call with a sub array.
Check length in advance (spelling matters ... arr) and return zero for unrachable values.
Use Array#slice instead of Array#splice (prevent mutation) and take the index, not the value of the item.
Finally return one plus the count of left or right side.
function binarySearch(array, number) {
console.log(...array);
var mid = Math.floor(array.length / 2);
if (number === array[mid]) return 1;
if (array.length <= 1) return 0;
return number < array[mid]
? 1 + binarySearch(array.slice(0, mid), number)
: 1 + binarySearch(array.slice(mid), number);
}
console.log('count:', binarySearch([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 4));
I worked on a problem where you are given an array of numbers and a target sum, and it's your job to find a pair of numbers that sum up to the target number. Here was my solution using simple nested for loops:
function findPairForSum(integers, target) {
var output = [];
for (var i = 0; i < integers.length; i++) {
for (var j = 0; j < integers.length; j++) {
if (i !== j && integers[i] + integers[j] === target) {
output.push(integers[i], integers[j]);
return output;
}
}
}
return 'not possible';
}
findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [4, 5]
My question is, is there a cleaner way to write this solution using higher order functions (perhaps forEach?)
Here was my attempt to use forEach:
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum) {
integers.forEach(function(secondNum) {
if (firstNum + secondNum === target) {
output.push(firstNum, secondNum);
}
})
})
if (output === []) {
return 'not possible';
}
return output;
}
findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [ 4, 5, 5, 4 ]
I tried putting a return after the two pushes, but it did not return anything. So instead, I put the return at the very end.
Why won't it return after the initial two pushes? I want it to stop right there, and only push the two numbers. Instead, by putting the return at the end, it pushed 4 numbers. It should be [4,5] but I got something like [4,5,5,4].
Any advice and help would be much appreciated!
Assume we have the following set of numbers, and we must find a subset of 2 numbers whose sum is 9:
Numbers: 4, 5, 6
Your current code iterates both with i and j from 0 to length. This means that the following iterations match the condition:
Indices: 0, 1, 2
Numbers: 4, 5, 6 // (i) (j)
---------------- // ↓ ↓
i j // Numbers[0] + Numbers[1] === 9
j i // Numbers[1] + Numbers[0] === 9
As you can see, the numbers 4 and 5 are matched twice, in 2 iterations:
i === 0 && j === 1
i === 1 && j === 0
You can avoid this by making sure one simple condition is met:
j must at all times be greater than i
This condition can be met met by initializing j with i + 1 in the inner for loop:
for (var i = 0; i < integers.length; i++) {
for (var j = i + 1; j < integers.length; j++) {
// ...
}
}
This way, j can never be 0 when i is 1, because the inner for-loop will run to completion before i is ever incremented once more. Once that happens, a brand new inner for-loop is created, in which j is again set to i + 1. The following diagram is the result:
Indices: 0, 1, 2
Numbers: 4, 5, 6
----------------
i j
X i // ← j can never be 0 if (i === 1),
// so the same set is never evaluated twice.
In other words, only the following combinations for i and j are checked at most:
Indices: 0, 1, 2
----------------
i j
i j
i j
is there a cleaner way to write this solution using higher order functions (perhaps forEach?)
A for loop is actually a fine solution for your use-case. They allow you to break early - after the first time you find a valid pair of numbers. forEach or other array iterator functions on the other hand will always continue until all set indices are visited.
You are actually breaking early in your first example with the statement return output;
When you use forEach on a set of numbers with multiple valid sets, you'll always get back all numbers involved:
Indices: 0, 1, 2, 3
Numbers: 4, 5, 6, 3 // (i) (j)
------------------- // ↓ ↓
i j // Numbers[0] + Numbers[1] === 4 + 5 === 9
i j // Numbers[2] + Numbers[3] === 6 + 3 === 9
forEach, map, reduce and the like do not allow you to break early. The following snippet demonstrates this issue of the diagram above:
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum, i) {
// slice(i + 1) has the same effect as for (var j = i + 1; ...)
integers.slice(i + 1).forEach(function(secondNum, j) {
if (firstNum + secondNum === target) {
// There is no way here to stop the iteration of either
// forEach call... T_T
output.push(firstNum, secondNum);
}
});
})
if (output.length) {
return output;
}
return 'not possible';
}
console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5, 6, 3]
This is why I highly recommend sticking with the for loops for this specific use case. With for loop you can simply return as you already did as soon as you encounter a valid set of numbers:
function findPairForSum(integers, target) {
for (var i = 0; i < integers.length; i++) {
for (var j = i + 1; j < integers.length; j++) {
if (integers[i] + integers[j] === target) {
return [integers[i], integers[j]];
}
}
}
return 'not possible';
}
console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5]
This could be your solution:
function findPairForSum(arr, sum) {
var pairs = [];
arr.forEach(n1 => {
var n2 = arr.find(n2 => n1 + n2 == sum)
if (n2) pairs.push([n1, n2]);
});
return pairs;
}
var sums = findPairForSum([3, 34, 4, 12, 6, 2], 9);
console.log(sums)
The problem is, you iterate from the start of the array for the inner loop. You could use a copy which starts at the index of the outer loop plus one and exit early on a found value.
But this does not solves the problem with multiple pairs. The result is simply wrong.
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum, i) {
integers.slice(i + 1).some(function(secondNum) {
if (firstNum + secondNum === target) {
output.push(firstNum, secondNum);
return true;
}
});
});
return output.length && output || 'not possible';
}
// console.log(findPairForSum([3, 34, 4, 12, 5, 2], 9));
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
For a solution, you need to remember which pairs are used. This approach works with only one loop and a hash table for counting missing values.
If a pair is found, the counter is decremented and the two values are pushed to the result set.
function findPairForSum(integers, target) {
var hash = Object.create(null),
output = [];
integers.forEach(function(value) {
if (hash[value]) {
output.push(target - value, value);
hash[value]--;
return;
}
hash[target - value] = (hash[target - value] || 0) + 1;
});
return output.length && output || 'not possible';
}
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
This is expected, since you didn't compare the indexes.
This inner array should only loop through the indexes which larger than the outer index.
You can achieve this by using the 2nd parameter, index, in forEach's callback function:
const ints = [3, 34, 4, 12, 5, 6, 2];
function findPairForSum(integers, target) {
let result;
integers.forEach((val1, idx1) => {
integers.forEach((val2, idx2) => {
if (idx1 < idx2 && val1 + val2 === target) {
result = [val1, val2];
}
})
})
return result;
}
console.log(findPairForSum(ints, 9));
Use can reduce your array into another which has sum equals target value:
const ints = [3, 34, 4, 12, 6, 2];
const value = 9;
const resp = ints.reduce((acc, ele, idx, self) => {
let found = self.find(x => x + ele == value)
return found ? [found, ele] : acc;
}, []);
console.log(resp); // [3, 6]
You can use Array.prototype.some which will stop execution as soon as the condition becomes true. See below code.
function findPairForSum(arr, sum) {
var pairs = [];
arr.some(n1 => {
var n2 = arr.find(n2 => n1 + n2 == sum)
if (n2) {
pairs.push(n1, n2); return true;
};
return false;
});
return pairs.length > 0 ? pairs : "not possible";
}
console.log(findPairForSum([3, 34, 4, 12, 7, 2], 9));
I'm trying to solve a basic javascript algorithm and i'm kinda stuck, here is the question:
Given an array of integers, find the pair of adjacent elements that
has the largest product and return that product.
Example
For inputArray = [3, 6, -2, -5, 7, 3], the output should be
adjacentElementsProduct(inputArray) = 21.
7 and 3 produce the largest product.
Here is my code, i can't find the problem but in the tests it says that it returns null:
function adjacentElementsProduct(inputArray) {
var cb;
for(var i=0;i<inputArray.length;i++){
if(inputArray[i] !== inputArray[inputArray.length-1]){
if(inputArray[i]*inputArray[i+1] > cb){
cb = inputArray[i]*inputArray[i+1];
}
}
}
return cb;
}
What is my problem and what i need to change?
What you ultimately want to do is iterate through the array excluding the last member, and compare a product of each current item with its next adjacent member to that of the largest one found thus far.
You can use .slice() and .reduce() for this.
function adjacentElementsProduct(arr) {
return arr.slice(0, -1)
.reduce((max, n, i) => Math.max(max, n * arr[i + 1]), -Infinity)
}
console.log(adjacentElementsProduct([3, 6, -2, -5, 7, 3]));
An alternate solution would be to create an array of products using .map() after doing the same .slice(), and pass that array's members to Math.max.
function adjacentElementsProduct(arr) {
return Math.max(...arr.slice(0, -1).map((n, i) => n * arr[i + 1]))
}
console.log(adjacentElementsProduct([3, 6, -2, -5, 7, 3]));
The problem with your code is you never initialized cb. So the comparison with cb is always invalid. Here is the correct version of your code -
function adjacentElementsProduct(inputArray) {
var cb = Number.NEGATIVE_INFINITY;
for(var i=0;i<inputArray.length-1;i++){
if(inputArray[i]*inputArray[i+1] > cb){
cb = inputArray[i]*inputArray[i+1];
}
}
return cb;
}
console.log(adjacentElementsProduct([3, 6, -2, -5, 7, 7]))
Since you need to use pairs of elements - you can just run through it and keep store maximum product value, something like this:
function adjacentElementsProduct(items) {
var product = 0;
for (var i = 0; i < items.length - 1; i++) {
product = Math.max(product, items[i] * items[i + 1]);
}
return product;
}
console.log(adjacentElementsProduct([3, 6, -2, -5, 7, 3]));
Using reduce we can simplify the amount of code.
var a = [3, 6, -2, -2, 7, 3].reduce(function(a, b, i, arr){
if (b*arr[i-1] > a)
{
a = b*arr[i-1];
}
return a;
})
console.log(a)
First of all, you could iterate from index 1 to the end and use i - 1 and i for adjacent elements. Then you could check if you are in iteration one and take the value or if the multiplication is greater then the old value, then assing the greater product.
function adjacentElementsProduct(inputArray) {
var cb, i;
for (i = 1; i < inputArray.length; i++) {
if (i === 1 || inputArray[i - 1] * inputArray[i] > cb) {
cb = inputArray[i - 1] * inputArray[i];
}
}
return cb;
}
console.log(adjacentElementsProduct([3, 6, -2, -5, 7, 3]));
More generic solution:
This will work for every array with negatives and non negatives numbers.
int adjacentElementsProduct(int[] inputArray) {
int length = inputArray.Length;
int max = Number.NEGATIVE_INFINITY;
for (int i = 0; i < length - 1; i++ ) {
max = Math.Max(max, inputArray[i] * inputArray[i+1]);
}
return max;
}
int adjacentElementsProduct(std::vector<int> inputArray) {
int n=inputArray.size();
int p=1;
int maxp=inputArray[0]*inputArray[1];
for(int i=0;i<n-1;i++){
p=inputArray[i]*inputArray[i+1];
if(p>maxp){
maxp=p;
}
}
return maxp;
}
Here is how you will do that in Python:
def adjacentElementsProduct(inputArray):
max = inputArray[0]* inputArray[1]
for i in range(0, len(inputArray)-1):
if inputArray[i] * inputArray[i+1] > max :
max = inputArray[i] * inputArray[i+1]
i+1
else:
i+1
return max
Or you can do it in one line like:
def adjacentElementsProduct(inputArray):
return max([inputArray[i] * inputArray[i+1] for i in range(len(inputArray)-1)])
function largetProduct(inputArray) {
let pairs=[];
for(var i = 0;i<inputArray.length ;i+=2){
pairs.push(inputArray.slice(i,i+2))
}
let products = pairs.map(v=> v[0]*v[1] || 1);
return (Math.max.apply(0,products));
}