JS: Finding unpaired elements in an array - javascript

I have the following question (this is not school -- just code site practice questions) and I can't see what my solution is missing.
A non-empty array A consisting of N integers is given. The array contains an odd number of elements, and each element of the array can be paired with another element that has the same value, except for one element that is left unpaired.
Assume that:
*N is an odd integer within the range [1..1,000,000];
*each element of array A is an integer within the range [1..1,000,000,000];
*all but one of the values in A occur an even number of times.
EX: A = [9,3,9,3,9,7,9]
Result: 7
The official solution is using the bitwise XOR operator :
function solution(A) {
var agg = 0;
for(var i=0; i<A.length; i++) {
agg ^= A[i];
}
return agg;
}
My first instinct was to keep track of the occurrences of each value in a Map lookup table and returning the key whose only value appeared once.
function solution(A) {
if (A.length < 1) {return 0}
let map = new Map();
let res = A[0]
for (var x = 0; x < A.length; x++) {
if (map.has(A[x])) {
map.set(A[x], map.get(A[x]) + 1)
} else {
map.set(A[x], 1)
}
}
for ([key,value] of map.entries()) {
if (value===1) {
res = key
}
}
return res;
}
I feel like I handled any edge cases but I'm still failing some tests and it's coming back with a 66% correct by the automated scorer.

You could use a Set and check if deletion deletes an item or not. If not, then add the value to the set.
function check(array) {
var s = new Set;
array.forEach(v => s.delete(v) || s.add(v));
return s.values().next().value;
}
console.log(check([9, 3, 9, 7, 3, 9, 9])); // 7

You're not accounting for cases like this:
[ 1, 1, 2, 2, 2 ] => the last 2 is left unpaired
So your condition should be if ( value % 2 ) instead of if ( value === 1 ).
I think also there is not much benefit to using a Map rather than just a plain object.

The official solution works due to the properties of the bitwise XOR (^), namely the fact that a ^ a == 0, a ^ 0 == a, and that the operation is commutative and associative. This means that any two equal elements in the array will cancel each other out to become zero, so all numbers appearing an even amount of times will be removed and only the number with an odd frequency will remain. The solution can be simplified using Array#reduce.
function findOdd(arr) {
return arr.reduce((a,c)=>a ^ c, 0);
}

You need not to make a count of each and traverse again, if you are sure that there will be exactly one number which will occur odd number of times. you can sum the array and do + when odd entry and - when even entry (to dismiss it back) and in the hash (map or object) you can just toggle for subsequent entry of each number.
Here is an example:
let inputArray1 = [10,20,30,10,50,20,20,70,20,70,50, 30,50], //50 -> 3 times
inputArray2 = [10,20,30,20,10], //30 -> 1 time
inputArray3 = [7,7,7,7,3,2,7,2,3,5,7]; //5 -> 1 time
let getOddOccuence = arr => {
let hash = {};
return arr.reduce((sum, n) => sum + ((hash[n] = !hash[n]) ? n : -n), 0);
}
console.log('Input Array 1: ', getOddOccuence(inputArray1));
console.log('Input Array 2: ', getOddOccuence(inputArray2));
console.log('Input Array 3: ', getOddOccuence(inputArray3));
In case the input contains multiple or no numbers having odd number of occurance (if you are not sure there) then you have already the hash (and you can ignore performing sum) and return the keys of hash (where value is true (and not checking with %2 and then consider as truthy or false in case of you have count))

function solution(A) {
let result = 0;
for (let element of A) {
// Apply Bitwise XOR to the current and next element
result ^= element;
}
return result;
}
const unpaired = solution([9, 3, 9, 3, 9, 7, 9]);
console.log(unpaired);
Source: https://gist.github.com/k0ff33/3eb60cfb976dee0a0a969fc9f84ae145

Related

firstDuplicate question on CodeSignal in Javascript

I couldn't figure out why I passed 22/23 on this challenge and not able to solve the last test case since it was hidden.. The feedback from the CodeSignal is
Tests passed: 22/23. Execution time limit exceeded: Program exceeded
the execution time limit. Make sure that it completes execution in a
few seconds for any possible input.
Challenge
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
Example
For a = [2, 1, 3, 5, 3, 2], the output should be solution(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than the second occurrence of 2 does, so the answer is 3.
For a = [2, 2], the output should be solution(a) = 2;
For a = [2, 4, 3, 5, 1], the output should be solution(a) = -1.
Input/Output
[execution time limit] 4 seconds (js)
[input] array.integer a
Guaranteed constraints:
1 ≤ a.length ≤ 105,
1 ≤ a[i] ≤ a.length.
[output] integer
The element in a that occurs in the array more than once and has the minimal index for its second occurrence. If there are no such elements, return -1.
My code
function solution(a) {
let first = Infinity
for ( let i = 0; i<a.length; i++ ) {
let pointer = i+1;
while (pointer <a.length) {
if (a[i] === a[pointer] && pointer<first) {
first = pointer;
}
pointer +=1
}
}
if (first === Infinity) {
return -1
}
return a[first]
}
Thank you.
In bad cases, you're iterating over the whole array for every element in it - O(n ^ 2). The inner while(pointer < a.length) results in the argument taking too much time.
Instead, make a Set of elements found so far, and return when the first duplicate element is found (which will be the minimal second index).
const solution = (a) => {
const set = new Set();
for (const item of arr) {
if (set.has(item)) return item;
set.add(item);
}
return -1;
};
Since this has no nested loop (.has and .add is O(1)), this is O(n) overall, which should be quick enough.

Why does an object exist in two sum solution? [duplicate]

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])];
}
}
}
}

Refactor from Procedural Paradigm to Functional Paradigm

In the process of learning functional programming, I am trying to refactor the following code using map, filter, and/or reduce.
I see that I can deal with the conditional using the filter method, but don't know how to handle the repeated assignment so I can avoid use of a for loop.
I am thinking that I would use the map method to handle the diff assignments, and chain a filter method that would deal with the conditional. Am I on the right track?
Would someone be kind enough to refactor the following code in the functional paradigm and explain. Thanks.
This function finds the first non-consecutive number in an array.
function firstNonConsecutive (arr) {
var diff = 0;
for(var i = 0; i < arr.length; i++) {
diff = arr[i+1] - arr[i];
if(diff > 1) {
return arr[i+1];
}
}
return null;
Consider using Array.find https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find, like most functional array functions it takes a callback/predicate that takes 3 parameters, the item, the index and the whole array. With this you can look ahead/behind in the same way you currently do. Like this:
function firstNonConsecutive2(arr) {
return arr.find((item, index, array) => {
const diff = array[index - 1] - item; // Use index -1 to look behind instead of ahead since we want to return/find the item that is non-consecutive
return diff === 0; // I think this was a small bug in your version which worked if the numbers were incrementing only
});
}
In the first iteration of the find "loop" it'll try to diff undefined with for example 1, which is NaN, NaN is not equal to 0 so it keeps searching. Next it'll try maybe 1 and 2 so diff becomes -1 so it keeps searching. Until it reaches for example 5 and 5, which diffs to 0 so the find predicate is now true, so it will return the second 5 since that is the current item, we're looking behind us by using index - 1.
Let me know if you want further explanation of something!
If you are looking into fp, then also recursion would find a good application here:
const firstNonConsecutive = (list) => {
if (!list.length) {
// list is empty, not found
return -1;
}
const [head, ...tail] = list;
const [n] = tail;
if (n - 1 !== head) {
// found
return n;
}
// yet another round
return firstNonConsecutive(tail);
};
console.log(
firstNonConsecutive([1, 2, 3, 4, 5, 6, 7, 9, 10]),
);
https://en.wikipedia.org/wiki/Recursion_(computer_science)
You want to use Array.find, not .map, .filter, or .reduce. You could find a way to use those, but they waste time because they don't return as soon as the first match is found.
Here are some progressively more verbose solutions to help you understand how the first one works.
The second is the most functional, because it's declarative unlike the first.
array.find(nonConsecutive) reads close to plain English and declares what you want to do, leaving the imperative implementation details hidden away inside the nonConsecutive function.
const array = [1, 2, 3, 4, 5, 6, 7, 9, 10];
console.log(
array.find((n, i) => i && n != array[i - 1] + 1) // 9
);
const nonConsecutive = (n, i, arr) => i && n != arr[i - 1] + 1;
console.log(
array.find(nonConsecutive) // 9
);
console.log(
array.find(function (number, index) { // we don't need third "array" argument because the array is already in scope.
if (index == 0) return false; // if index is zero, return. Otherwise, next line would access index -1.
if (number != array[index - 1] + 1) return true; // if number is not equal to the the previous number, plus one, it's not consecutive. Return it.
return false; // if we reach this line than the number must be consecutive, so return false.
}) // 9
);
Recursion by mathematical induction -
If the first element, a, or the second element, b, are null, return undefined
(induction) Neither the first element, a, nor the second element, b are null. If b is consecutive to a, return the recursive result of the smaller problem
(induction) Neither the first element, a, nor the second element, b, are null and b is not consecutive to a. Return the answer, b.
const firstNonConsecutive = ([ a, b, ...more ]) =>
a == null || b == null
? undefined // 1
: b === a + 1
? firstNonConsecutive([ b, ...more ]) // 2
: b // 3
console.log(firstNonConsecutive([ 4, 5, 6, 8, 9, 10 ]))
// 8
console.log(firstNonConsecutive([ 7, 8, 9, 10, 13, 14 ]))
// 13
console.log(firstNonConsecutive([ 99 ]))
// undefined
console.log(firstNonConsecutive([]))
// undefined

Find all pairs that sum to a target value

I've been looking through this example which is a supposedly faster way of matching than using multiple loops. I've seen an explanation here but it makes absolutely no sense to me.
Can someone please break this down for me and what target - arr[i] is been used for?
const arr = [7, 0, -4, 5, 2, 3];
const twoSum = (arr, target) => {
let map = {}
let results = [];
for (let i=0; i<arr.length; i++) {
if (map[arr[i]] !== undefined) {
results.push([map[arr[i]], arr[i]])
} else {
map[target - arr[i]] = arr[i];
}
}
return results;
}
console.log('twoSum = ', twoSum(arr, 5));
Suppose target is t. Given a value x in the array, you want to know if there exists a value t - x in the array, in which case the sum is t - x + x = t.
So you go through the array, to mark the fact you see x in the array you mark the entry t - x in a map. Later when you encounter t - x in the array you check entry t - x in the map, and if it is populated then you know you previously saw x, which means you have the pair x and t - x. The way I just described it sounds like two loops through the array, but you can do these two things in just one loop and it works the same.
If a map entry is populated then you previously saw its pair value, if not populated you mark the map to see if you encounter that pair value later.
You could even make it more faster, without storing of the actual value, because you are looking for a two values and one is known, you know the other as well.
const
arr = [7, 0, -4, 5, 2, 3],
twoSum = (arr, target) => {
let map = {},
results = [];
for (let i = 0; i < arr.length; i++) {
if (map[arr[i]]) { // straight check
results.push([target - arr[i], arr[i]]); // take delta
continue;
}
map[target - arr[i]] = true;
}
return results;
};
console.log('twoSum = ', twoSum(arr, 5));
There seems to be a mistake in the explanation you linked to: where it says, "Our new key/value pair is 5: 5. Our hash map now contains two entries: {7: -2, 5: 5}." The new key/value (and this is achieved correctly in the code) is 5: 0.
To understand how it works suppose our array is [2, 6, 3] and the target is 5. Once we see 2, we'd like to know if the array has its partner that together sums to 5.
x + 2 = 5
x = 5 - 2
x = 3
So we're looking for 3. Now, the JavaScript map object allows us to efficiently retrieve a value if we know its key. So we set our key to 3 - this way if we see a 3 later, we can quickly respond. Remember that we haven't seen 3 yet. We're just setting the key to quickly alert us if we see it that we've seen its partner, 2, already.
Now we continue along the array. We pass by 6 but there's no key 6 in the map so we add it to the map and continue. When we get to 3, we say, "Aha!", the map having 3 is alerting us that we've seen its partner that together sums to 5. We push the result, 3 (the current arr[i]) and the value stored in the map under the 3 key (map[arr[i]]), which was the 2 we saw earlier.
The algorithm is creating pairs by examining the currently processed item with previously seen items.
So, it requires a memory for the previously seen items, and that's why map factors into the solution.
Let's analyse the loop in the solution:
for (let i=0; i<arr.length; i++) {
if (map[arr[i]] !== undefined) {
results.push([map[arr[i]], arr[i]])
} else {
map[target - arr[i]] = arr[i];
}
}
It's equivalent to the following:
for ( let i = 0; i < arr.length; i++ ) {
// Any item in the array that's not in the memory
// 1. should primarily be stored
// 2. such that it's potential pair is stored as a key that's mapped to a value which is the item
if ( map[ arr[ i ] ] === undefined ) {
map[ target - arr[ i ] ] = arr[ i ];
// Examine pairs only in iterations with odd numbered indices.
// Why? - For the first iteration, the memory is empty...
continue;
}
// this item’s pair is known, so store the pair in the result list
results.push( [ map[ arr[ i ] ], arr[ i ] ] );
}

How to understand this recursion

Hello all I am trying to understand this solution to combination sum.
function combinationSum(candidates, target) {
var result = [];
if ((candidates == null) || (candidates.length == 0)) {
return result;
}
var cur = [];
candidates = candidates.sort((a, b) => a - b)
csh(candidates, target, cur, result, 0);
return result;
};
function csh(cand, target, cur, result, j) {
//console.log(cur);
if (target == 0) {
var temp = cur.slice();
result.push(temp);
return;
}
for (var i = j; i < cand.length; i++) {
if (target < cand[i]) {
return;
}
//console.log(cur);
cur.push(cand[i]);
console.log(cur);
csh(cand, target - cand[i], cur, result, i);
cur.pop();
}
}
https://leetcode.com/problems/combination-sum/description/
While I understand the basic principles of recursion this problem is a little bit lost on me. So for example for the input:
candidates = [2,3,6,7]
target = 7
When you first enter the function cur is empty so our first iteration is:
[],
[2],
[2,2]
And then we keep adding cand[i] which is currently 2
[2,2,2]
However at this point, target = 1 which is less than cand[i] which is 2 so we return. And since we're returning we pop off the stack which pops the last 2 off the stack. Since we've returned we increment i and then we add 3 to cur
[2,2,3]
Since our target array is equal to 0 we now return again and my question is, at this point do we keep returning until cur is empty and continue the function like the following?
[2,2]
[2]
[]
[6]
[]
[7]
I'm just trying to understand what is being done in this function.
target is local to each invocation of the function. target is 0 only for some invocations of the function. Notice that the recursive invocation is:
csh(cand, target - cand[i], cur, result, i);
The target in that scope has not change, but the invocation of csh currently being entered will have a lower value for its target. When that function returns and the program flow reenters that other level, we resume using the higher value of target, insted of the reduce value target - cand[i] that was supplied to the subcall.
The algorithm will try all other possibilities on the [2,2,...] path as well, before changing the second element to the next alternative. Then it will explore the [2,3,...] space, and the [2,6,...] space, and ultimately all the [3,...], [6,...] and [7,...] possibilities as well.
The algorithm always goes as deep as a possible (i.e., as long of an array as possible) when it can do so without going over the original limit.
Note that it does not produce [2,3,2], because an earlier candidate cannot come after a later one (so a 2 can never be subsequent to a 3 in a result). It enforces this by making the for look start at i = j, where j is the array-depth of the last candidate used, so when the result-in-progress ends with the nth candidate, it only considers nth and higher candidates. this is of practical value because the algorithm only returns one permutation of each value result set: [2,2,3] and [2,3,2] contain the same set of values.
I completely understand that recursion can be very difficult to understand and to explain as well, but here is my take on it.
When csh is called for the 1st time, this is what is being passed
csh(cand, 7, [], [], 0)
Now from the for loop, i = 0, function called is
csh(cand, 5, [2], [], 0)
from the loop, i = 0, function called is
csh(cand, 3, [2,2], [], 0)
from the loop, i = 0, function called is
csh(cand, 1, [2,2,2],[],0)
from the for loop, target(1) < cand[0](2), so return to step Step 4 and pop the last 2 from [2,2,2] resulting in [2,2]
from the loop i = 1, function called is
csh(cand, 0, [2,2,3], [], 1)
here, target == 0 condition is met. so, [2,2,3] is pushed in the result. and then return to step 4. again, 3 is popped from [2,2,3].
from the loop i = 2, target(3) < cand[2](6), so return to step 3. and pop 2 from [2,2] resulting in [2].
from the loop i = 1, function called is
csh(cand, 2, [2,3], [[2,2,3]], 1)
from the loop i = 1, target(2) < cand[1](1) so return to step 9.
and so no...
Basically, each and every combination will be checked.
[2,2,2]
[2,2,3] --> added to result
[2,3,3]
[2,6]
[2,7]
[3,3,3]
[3,6]
[3,7]
[6,6]
[6,7]
[7] --> added to res

Categories

Resources