While solving online code exercises, I came across this one:
Given a 1-dimensional array of numbers and the number of queries, where each query has start index a, end index b and a number c, find the sum of numbers between indexes a and b (inclusive). For each occurrence of zero within the range [a,b], add the value of c to the sum. For example, numbers = [4,6,0,10], queries = [1,3,20] => for this example we need to get the sum of [4,6,0] (indexes 1-3), and because [4,6,0] has 0, we also need to add 20.
This is my code so far:
function findSum(numbers, queries) {
//declare empty array that will store the numbers
let arr = []
// declare initial sum
let sum = 0;
// get the last element of queries (c)
let lastElement = queries[0].pop()
// loop through queries and push numbers to arr, to sum them in the end
queries[0].slice(0, 2).forEach(x => {
arr.push(numbers[x - 1])
})
// check if arr has 0
let zero = arr.filter(el => el === 0)
// if arr has 0, according to the instructions we need to add the c of the q
if (zero.length != 0) {
sum = arr.reduce((a, b) => a + b, 0) + lastElement
}
else {
sum = arr.reduce((a, b) => a + b, 0)
}
return sum
}
My code works if queries is an array, but in some test cases queries may be array of arrays like [ [ 2, 2, 20 ], [ 1, 2, 10 ] ]. I don't know know how to check the numbers in case if queries is array of arrays. Any suggestions are greatly appreciated.
in some test cases queries may be array of arrays
I would expect that this would always be the case, not just in some cases. This is also clear from your code:
queries[0].pop()
This assumes a 2-dimensional array! The problem is not that you sometimes get a 1-dimensional array and other times a 2-dimensional array. The problem is that although you always get a 2-dimensional array, your code is only looking at the first query -- the one that sits at queries[0].
Instead, you should loop over all queries.
I also assume that the return value of your function must be an array, having an answer for each of the queries. This means that you probably want to have code like this:
function findSum(numbers, queries) {
return queries.map(query => {
// solve the single query
return sum;
});
}
Note that your code is not making the sum correctly, as your arr will have a length of 2 (arr.push(numbers[x - 1]) is executed exactly twice), yet the query could indicate a range with 100 values and you should derive the sum of those 100 values, not just of two.
But even if you fix all that, you'll end up with an inefficient solution that will have to iterate over many values in the input array multiple times. This needs a smarter approach.
Try to think of a way to analyse the input before processing any queries yet. Would there be something useful you could build that would help to quickly get a sum of a subarray without having to iterate that subsection again?
Here are some hints:
Hint #1
Use the following truth:
sum(numbers.slice(start, end)) == sum(numbers.slice(0, end)) - sum(numbers.slice(0, start - 1))
Hint #2
What if you would know the sum from the start of the array to any given index? Like a running sum... So for numbers=[4, 8, 0, 3] you would know [4, 12, 12, 15]. Would that help in calculating a sum for a certain range of [start, end]?
Hint #3
How could you apply the same principle for the special treatment of zeroes?
Related
Im just wondering who can explain the algorithm of this solution step by step. I dont know how hashmap works. Can you also give a basic examples using a hashmap for me to understand this algorithm. Thank you!
var twoSum = function(nums, target) {
let hash = {};
for(let i = 0; i < nums.length; i++) {
const n = nums[i];
if(hash[target - n] !== undefined) {
return [hash[target - n], i];
}
hash[n] = i;
}
return [];
}
Your code takes an array of numbers and a target number/sum. It then returns the indexes in the array for two numbers which add up to the target number/sum.
Consider an array of numbers such as [1, 2, 3] and a target of 5. Your task is to find the two numbers in this array which add to 5. One way you can approach this problem is by looping over each number in your array and asking yourself "Is there a number (which I have already seen in my array) which I can add to the current number to get my target sum?".
Well, if we loop over the example array of [1, 2, 3] we first start at index 0 with the number 1. Currently, there are no numbers which we have already seen that we can add with 1 to get our target of 5 as we haven't looped over any numbers yet.
So, so far, we have met the number 1, which was at index 0. This is stored in the hashmap (ie object) as {'1': 0}. Where the key is the number and the value (0) is the index it was seen at. The purpose of the object is to store the numbers we have seen and the indexes they appear at.
Next, the loop continues to index 1, with the current number being 2. We can now ask ourselves the question: Is there a number which I have already seen in my array that I can add to my current number of 2 to get the target sum of 5. The amount needed to add to the current number to get to the target can be obtained by doing target-currentNumber. In this case, we are currently on 2, so we need to add 3 to get to our target sum of 5. Using the hashmap/object, we can check if we have already seen the number 3. To do this, we can try and access the object 3 key by doing obj[target-currentNumber]. Currently, our object only has the key of '1', so when we try and access the 3 key you'll get undefined. This means we haven't seen the number 3 yet, so, as of now, there isn't anything we can add to 2 to get our target sum.
So now our object/hashmap looks like {'1': 0, '2': 1}, as we have seen the number 1 which was at index 0, and we have seen the number 2 which was at index 1.
Finally, we reach the last number in your array which is at index 2. Index 2 of the array holds the number 3. Now again, we ask ourselves the question: Is there a number we have already seen which we can add to 3 (our current number) to get the target sum?. The number we need to add to 3 to get our target number of 5 is 2 (obtained by doing target-currentNumber). We can now check our object to see if we have already seen a number 2 in the array. To do so we can use obj[target-currentNumber] to get the value stored at the key 2, which stores the index of 1. This means that the number 2 does exist in the array, and so we can add it to 3 to reach our target. Since the value was in the object, we can now return our findings. That being the index of where the seen number occurred, and the index of the current number.
In general, the object is used to keep track of all the previously seen numbers in your array and keep a value of the index at which the number was seen at.
Here is an example of running your code. It returns [1, 2], as the numbers at indexes 1 and 2 can be added together to give the target sum of 5:
const twoSum = function(nums, target) {
const hash = {}; // Stores seen numbers: {seenNumber: indexItOccurred}
for (let i = 0; i < nums.length; i++) { // loop through all numbers
const n = nums[i]; // grab the current number `n`.
if (hash[target - n] !== undefined) { // check if the number we need to add to `n` to reach our target has been seen:
return [hash[target - n], i]; // grab the index of the seen number, and the index of the current number
}
hash[n] = i; // update our hash to include the. number we just saw along with its index.
}
return []; // If no numbers add up to equal the `target`, we can return an empty array
}
console.log(twoSum([1, 2, 3], 5)); // [1, 2]
A solution like this might seem over-engineered. You might be wondering why you can't just look at one number in the array, and then look at all the other numbers and see if you come across a number that adds up to equal the target. A solution like that would work perfectly fine, however, it's not very efficient. If you had N numbers in your array, in the worst case (where no two numbers add up to equal your target) you would need to loop through all of these N numbers - that means you would do N iterations. However, for each iteration where you look at a singular number, you would then need to look at each other number using a inner loop. This would mean that for each iteration of your outer loop you would do N iterations of your inner loop. This would result in you doing N*N or N2 work (O(N2) work). Unlike this approach, the solution described in the first half of this answer only needs to do N iterations over the entire array. Using the object, we can find whether or not a number is in the object in constant (O(1)) time, which means that the total work for the above algorithm is only O(N).
For further information about how objects work, you can read about bracket notation and other property accessor methods here.
You may want to check out this method, it worked so well for me and I have written a lot of comments on it to help even a beginner understand better.
let nums = [2, 7, 11, 15];
let target = 9;
function twoSums(arr, t){
let num1;
//create the variable for the first number
let num2;
//create the variable for the second number
let index1;
//create the variable for the index of the first number
let index2;
//create the variable for the index of the second number
for(let i = 0; i < arr.length; i++){
//make a for loop to loop through the array elements
num1 = arr[i];
//assign the array iteration, i, value to the num1 variable
//eg: num1 = arr[0] which is 2
num2 = t - num1;
//get the difference between the target and the number in num1.
//eg: t(9) - num1(2) = 7;
if(arr.includes(num2)){
//check to see if the num2 number, 7, is contained in the array;
index1 = arr.indexOf(num2);
//if yes get the index of the num2 value, 7, from the array,
// eg: the index of 7 in the array is 1;
index2 = arr.indexOf(num1)
//get the index of the num1 value, which is 2, theindex of 2 in the array is 0;
}
}
return(`[${index1}, ${index2}]`);
//return the indexes in block parenthesis. You may choose to create an array and push the values into it, but consider space complexities.
}
console.log(twoSums(nums, target));
//call the function. Remeber we already declared the values at the top already.
//In my opinion, this method is best, it considers both time complexity and space complexityat its lowest value.
//Time complexity: 0(n)
function twoSum(numbers, target) {
for (let i = 0; i < numbers.length; i++) {
for (let j = i + 1; j < numbers.length; j++) {
if (numbers[i] + numbers[j] === target) {
return [numbers.indexOf(numbers[i]), numbers.lastIndexOf(numbers[j])];
}
}
}
}
I'm working on creating a basic function that takes in 2 parameters -- array and num.
In the array are a list of numbers and the output could essentially generate 3 results:
0 with no two numbers that equal the sum equal to num.
1 variation of two numbers that is equal to the sum that is num
Multiple variations of 2 numbers that equal the sum that is num
I've been working with filter and reduce but haven't been able to produce the desired output.
Let's say I have a nums array of [3,6,9,18] and have a specified num value of 15.
var findNumSum = function(nums, num) {
function val(a, b) {
a + b === num;
var es = [a, b]
return es;
}
var result1 = nums.filter(val); // [3,6,9,18]
var result2 = nums.reduce(val); // [[6, 9], 18]] -- I've been able to isolate the num values but wasn't the result I was expecting. I'm still pretty fresh at this.
};
Let's assume you want to find sums for the number 6. Check the first number of the array, let it be 2. You now want to know if there's a 4 in you array, so you check that. Do this process for all the numbers in the array and remove duplicates.
Maybe this could help ?
Here is a little snippets along the lines of the previous suggestions:
const arr=[...Array(25)].map((_,v,)=>v), // create an array with 25 numbers
findsum=(ar,sum)=>
ar.reduce((a,c,i)=>
(c>sum || ar.slice(i+1).forEach(v=>
c+v-sum || a.push([c,v])),a)
,[] );
console.log(findsum(arr,27)) // find all possible pairs that add up to 27
Maybe it is helpful to you?
Only if the first condition c>sum is false the following ar.slice(i+1).forEach(...) will be executed. inside the forEach()-callback function the a.push([c,v]) will only be performed c+v-sum is "falsy" i. e. ==0.
I am trying to determine if the product of all the integers is even or odd.
I have a list of integers, and I want to check if the product of the integers is even or odd.
For example:
determineIfEvenOrOdd([6,7,9,9])
function determineIfEvenOrOdd(int_array) {
//Code here
}
I was thinking of looping through the array and multiplying the numbers to find out the product of the array integers. But then I thought it would be expensive to do this if the array was huge.
I am a beginner, and would like to know a possible approach for the solution.
If your list of numbers contains an even number, the product of all numbers will be even.
You can loop through the list of numbers and check each individual number for even-ness with a conditional statement like:
// Put this code inside function determineIfEvenOrOdd
var even = false;
for (let i=0; i<int_array.length; i++) {
if (i%2==0) {
even = true;
break;
}
}
An efficient way would be to check whether there is any number that is even, if so, the product is even. If there aren't any numbers that are even, then the product is odd.
function isProductEven(arr)
{
for (let i = 0; i < arr.length; i++)
if ((arr[i] & 1) === 0) return true;
return false;
}
console.log(isProductEven([6, 7, 9, 9]))
This outputs true as the product of these numbers is even.
The most concise solution would be this:
const isProductEven = arr =>
arr.some(e=>!(e%2));
This checks if at least one of the numbers in the array is even by testing if its remainder from division by 2 equals to 0. You can use it directly as well:
console.log([1,2,3].some(e=>!(e%2))); // true
console.log([1,3,5].some(e=>!(e%2))); // false
console.log([].some(e=>!(e%2))); // false
I usually implement Array.reduce to achieve this. It's easy to implement.
function isArrayProductEven(arr) {
return !(arr.reduce((a, b) => a * b, 1) % 2);
}
console.log(isArrayProductEven([1,2,3,4,5]));
console.log(isArrayProductEven([1,3,5,7,9]));
How this works is: multiply all numbers in the array and check the remainder of 2 (odd / even) to determine if the result is odd (false) or even (true).
How does the following code sort this array to be in numerical order?
var array=[25, 8, 7, 41]
array.sort(function(a,b){
return a - b
})
I know that if the result of the computation is...
Less than 0: "a" is sorted to be a lower index than "b".
Zero: "a" and "b" are considered equal, and no sorting is performed.
Greater than 0: "b" is sorted to be a lower index than "a".
Is the array sort callback function called many times during the course of the sort?
If so, I'd like to know which two numbers are passed into the function each time. I assumed it first took "25"(a) and "8"(b), followed by "7"(a) and "41"(b), so:
25(a) - 8(b) = 17 (greater than zero, so sort "b" to be a lower index than "a"): 8, 25
7(a) - 41(b) = -34 (less than zero, so sort "a" to be a lower index than "b": 7, 41
How are the two sets of numbers then sorted in relation to one another?
Please help a struggling newbie!
Is the array sort callback function called many times during the course of the sort?
Yes
If so, I'd like to know which two numbers are passed into the function each time
You could find out your self with:
array.sort((a,b) => {
console.log(`comparing ${a},${b}`);
return a > b ? 1
: a === b ? 0
: -1;
});
EDIT
This is the output I've got:
25,8
25,7
8,7
25,41
The JavaScript interpreter has some kind of sort algorithm implementation built into it. It calls the comparison function some number of times during the sorting operation. The number of times the comparison function gets called depends on the particular algorithm, the data to be sorted, and the order it is in prior to the sort.
Some sort algorithms perform poorly on already-sorted lists because it causes them to make far more comparisons than in the typical case. Others cope well with pre-sorted lists, but have other cases where they can be "tricked" into performing poorly.
There are many sorting algorithms in common use because no single algorithm is perfect for all purposes. The two most often used for generic sorting are Quicksort and merge sort. Quicksort is often the faster of the two, but merge sort has some nice properties that can make it a better overall choice. Merge sort is stable, while Quicksort is not. Both algorithms are parallelizable, but the way merge sort works makes a parallel implementation more efficient, all else being equal.
Your particular JavaScript interpreter may use one of those algorithms or something else entirely. The ECMAScript standard does not specify which algorithm a conforming implementation must use. It even explicitly disavows the need for stability.
Pairs of values are compared, one pair at a time. The pairs that are compared are an implementation detail--don't assume they will be the same on every browser. The callback can be anything (so you can sort strings or Roman numerals or anything else where you can come up with a function that returns 1,0,-1).
One thing to keep in mind with JavaScript's sort is that it is not guaranteed to be stable.
Deeply Knowledge
If the result is negative a is sorted before b.
If the result is positive b is sorted before a.
If the result is 0 no changes are done with the sort order of the two values.
NOTE:
This code is the view inside of the sort method step by step.
OUTPUT:
let arr = [90, 1, 20, 14, 3, 55];
var sortRes = [];
var copy = arr.slice(); //create duplicate array
var inc = 0; //inc meant increment
copy.sort((a, b) => {
sortRes[inc] = [ a, b, a-b ];
inc += 1;
return a - b;
});
var p = 0;
for (var i = 0; i < inc; i++) {
copy = arr.slice();
copy.sort((a, b) => {
p += 1;
if (p <= i ) {
return a - b;
}
else{
return false;
}
});
p = 0;
console.log(copy +' \t a: '+ sortRes[i][0] +' \tb: '+ sortRes[i][1] +'\tTotal: '+ sortRes[i][2]);
}
To help clarify the behavior of Array#sort and its comparator, consider this naive insertion sort taught in beginning programming courses:
const sort = arr => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && arr[j-1] > arr[j]; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array);
console.log("" + array);
Ignoring the choice of insertion sort as the algorithm, focus on the hardcoded comparator: arr[j-1] > arr[j]. This has two problems relevant to the discussion:
The > operator is invoked on pairs of array elements but many things you might want to sort such as objects don't respond to > in a reasonable way (the same would be true if we used -).
Even if you are working with numbers, oftentimes you want some other arrangement than the ascending sort that's been baked-in here.
We can fix these problems by adding a comparefn argument which you're familiar with:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array, (a, b) => a - b);
console.log("" + array);
sort(array, (a, b) => b - a);
console.log("" + array);
const objArray = [{id: "c"}, {id: "a"}, {id: "d"}, {id: "b"}];
sort(objArray, (a, b) => a.id.localeCompare(b.id));
console.log(JSON.stringify(objArray, null, 2));
Now the naive sort routine is generalized. You can see exactly when this callback is invoked, answering your first set of concerns:
Is the array sort callback function called many times during the course of the sort? If so, I'd like to know which two numbers are passed into the function each time
Running the code below shows that, yes, the function is called many times and you can use console.log to see which numbers were passed in:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
console.log("on our version:");
const array = [3, 0, 4, 5];
sort(array, (a, b) => console.log(a, b) || (a - b));
console.log("" + array);
console.log("on the builtin:");
console.log("" +
[3, 0, 4, 5].sort((a, b) => console.log(a, b) || (a - b))
);
You ask:
How are the two sets of numbers then sorted in relation to one another?
To be precise with terminology, a and b aren't sets of numbers--they're objects in the array (in your example, they're numbers).
The truth is, it doesn't matter how they're sorted because it's implementation-dependent. Had I used a different sort algorithm than insertion sort, the comparator would probably be invoked on different pairs of numbers, but at the end of the sort call, the invariant that matters to the JS programmer is that the result array is sorted according to the comparator, assuming the comparator returns values that adhere to the contract you stated (< 0 when a < b, 0 when a === b and > 0 when a > b).
In the same sense that I have the freedom to change my sort's implementation as long as I don't breach my specification, implementations of ECMAScript are free to choose the sort implementation within the confines of the language specification, so Array#sort will likely produce different comparator calls on different engines. One would not write code where the logic relies on some particular sequence of comparisons (nor should the comparator produce side effects in the first place).
For example, the V8 engine (at the time of writing) invokes Timsort when the array is larger than some precomputed number of elements and uses a binary insertion sort for small array chunks. However, it used to use quicksort which is unstable and would likely give a different sequence of arguments and calls to the comparator.
Since different sort implementations use the return value of the comparator function differently, this can lead to surprising behavior when the comparator doesn't adhere to the contract. See this thread for an example.
Is the array sort callback function called many times during the course of the sort?
Yes, that's exactly it. The callback is used to compare pairs of elements in the array as necessary to determine what order they should be in. That implementation of the comparison function is not atypical when dealing with a numeric sort. Details in the spec or on some other more readable sites.
Is the array sort callback function called many times during the course of the sort?
Since this is a comparison sort, given N items, the callback function should be invoked on average (N * Lg N) times for a fast sort like Quicksort. If the algorithm used is something like Bubble Sort, then the callback function will be invoked on average (N * N) times.
The minimum number of invocations for a comparison sort is (N-1) and that is only to detect an already sorted list (i.e. early out in Bubble Sort if no swaps occur).
Is the array sort callback function called many times during the course of the sort?
Yes
If so, I'd like to know which two numbers are passed into the function each time.
a: The first element for comparison.
b: The second element for comparison.
In the following example, a will be "2" and b will be "3" in the first iteration
How are the two sets of numbers then sorted in relation to one another?
Elements are sorted according to the return value of the compare function.
greater than 0: sort a after b
less than 0: sort a before b
equal to 0: keep original order of a and b
Here is an example
var arr = [3, 2, 1, 5, 4, 6, 7, 9, 8, 10];
console.log(arr.sort((a, b) => {
console.log(a - b, a, b);
//b-a if sorting in decending order
return a - b;
}));
I have a question. I'm looking for a way to get the higest unique number of an array.
var temp = [1, 8, 8, 8, 4, 2, 7, 7];
Now I want to get the output 4 since that is the unique highest number.
Is there a good & hopefully short way to do that?
Yes, there is:
Math.max(...temp.filter(el => temp.indexOf(el) == temp.lastIndexOf(el)))
Explanation:
First, get the elements which are unique in the array using Array#filter
temp.filter(el => temp.indexOf(el) === temp.lastIndexOf(el)) // [1, 4, 2]
Now, get the max of the numbers from the array using ES6 spread operator
Math.max(...array) // 4
This code is equivalent to
Math.max.apply(Math, array);
If you don't want to get fancy, you can use a sort and loop to check the minimal number of items:
var max = 0;
var reject = 0;
// sort the array in ascending order
temp.sort(function(a,b){return a-b});
for (var i = temp.length - 1; i > 0; i--) {
// find the largest one without a duplicate by iterating backwards
if (temp[i-1] == temp[i] || temp[i] == reject){
reject = temp[i];
console.log(reject+" ");
}
else {
max = temp[i];
break;
}
}
Using the spread operator you can find the hightest number easily
Math.max(...numArray);
The only thing left then is to either filter duplicates from the array beforehand, or remove all the elements that match your maximum number if its a duplicate.
remove beforeHand would be easiest in es6 like this.
Math.max(...numArray.filter(function(value){ return numArray.indexOf(value) === numArray.lastIndexOf(numArray);}));
For a non es6 compatible way to remove duplicates have a look at Remove Duplicates from JavaScript Array, the second answer contains an extensive examinations of several alternatives