Return missing number from Array (algorithm) - javascript

I'm working on an algorithm problem (on leetcode) which is asking the following:
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.
For example,
Given nums = [0, 1, 3] return 2.
My current answer is:
var missingNumber = function(nums) {
return nums.filter(function(item, index, arr) {
return arr[index] - arr[index - 1] > 1;
}).shift() - 1;
};
However, leetcode is using these two test cases (among some others) which make no sense to me:
Input: [0]
Expected: 1
Input: [0, 1]
Expected: 2
EDIT: also...
Input: [1]
Expected: 0
From what I understand, the algorithm is asking to return a single number that is missing from an array, given there is a number that is actually missing in the first place. Am I missing something here or are the instructions for this algorithm very unclear?

There is a different way to do it using XOR operation. The idea here is that a number XORed with itself will always be 0. We can store XORs of all the numbers from 0 to N in variable xor1 and XORs of all the numbers of our array in variable xor2. The XOR of xor1 and xor2 will be the missing number as it will only appear in xor1 and not in xor2.
function foo(arr){
var n = arr.length;
var xor1 = 0, xor2 = 0;
for(var i = 0;i <= n;i++)
xor1 ^= i;
for(var i = 0;i < n;i++)
xor2 ^= arr[i];
return xor1 ^ xor2;
}

The total of the integers from 1..n is:
So, the expected total of an array of length n with values from 0..n would be the same. The missing number would be the total minus the sum of the actual values in the array:
"use strict";
let missingNumber = function(nums) {
let n = nums.length;
let expected = n * (n + 1) / 2;
let total = nums.reduce((a, b) => a + b, 0);
return expected - total;
}

This is how I would implement it, you can loop until <= to the array length so if the passed in array passes the test it will try to look at nums[nums.length] which will be undefined and return i correctly. Return 0 if they pass in an empty array.
var missingNumber = function(nums){
for(var i = 0; i <= nums.length; i++){
if(nums[i] !== i) return i;
}
return 0;
}

Try using indexOf() method. It returns -1 if the item is not found.
nums = [0, 1, 3];
var missingNumber = function(nums){
for(i = 0; i <= nums.length; i++){
if(nums.indexOf(i) < 0 ) {
return i;
}
}
return 0;
}

Related

How can I find all first indexes of sequence of consecutive zeroes in an array?

I am trying to push all first indexes that point to a start of a sequence of consecutive 0s from the array A into a new array arr.
var C determines the amount of 0s in the sequence. For example, if C is 2, the algorithm will look for 00s, if C is 3 it will look for 000s and so on. N is the length of an array A. The algorithm seems to work, but for some reason the values in the new array arr are duplicated
var A = [1, 0, 0, 1];
var N = 4;
var C = 1;
function S(A, N, C) {
var arr = [];
for (var i = 0; i < N; i++) {
for (var j = 0; j <= C; j++) {
if ((A[i] == 0) && (A[i + j] == 0)) {
arr.push(i);
}
}
}
console.log(arr);
return -1;
}
/// console result:
Array(5)
0: 1
1: 1
2: 2
3: 2
//Expected:
0: 1
1: 2
First I would like to recommend that you use more descriptive variable names. The fact that you need to describe what each of them means, means that they are not descriptive enough.
Also your variable N seems redundant, because arrays already have a .length property that you can use to see how many elements are in there.
The source of your error seems to be that you use a nested loop. There is no need to use nested loops. You only need to go through all elements once and keep track of the repeated zeroes. Every time you encounter a non-zero value, you reset the sequence count to 0. If do encounter a zero you increment the sequence count and afterwards you check if the sequence count is equal to the number of zeroes you passed as an argument. In that case you want to push the first index to the resulting array and reset the sequence count to 0 again.
function getFirstIndexesOfSequenceOfConsecutiveZeroes(input, numberOfRepeatedZeroes) {
if (numberOfRepeatedZeroes <= 0) {
throw new Error("numberOfRepeatedZeroes need to be 1 or higher");
}
var firstIndexes = [];
let sequenceStartIndex;
let sequenceCount = 0;
for (var i = 0; i < input.length; i++) {
if (input[i] !== 0) {
sequenceCount = 0;
} else {
if (sequenceCount == 0) {
sequenceStartIndex = i;
}
sequenceCount++;
}
if (sequenceCount === numberOfRepeatedZeroes) {
firstIndexes.push(sequenceStartIndex);
sequenceCount = 0;
}
}
return firstIndexes;
}
let input = [1, 0, 0, 1];
let numberOfRepeatedZeroes = 1;
console.log(getFirstIndexesOfSequenceOfConsecutiveZeroes(input, numberOfRepeatedZeroes));
Try:
function S(A, B, C) {
var arr = [];
for (var i = 0; i < B; i++) {
for (var j = 0; j <= C; j++) {
if ((A[i] == 0) && (A[i + j] == 0) && !arr.includes(i)) {
arr.push(i);
}
}
}
console.log(arr);
return -1;
}
With this simple add in the if, you check if the value is already in your array.

Algorithm to find all possible arrays of size L that sum up to N or less

I want to find all possible arrays -of non-negative integers- of size L that sum up to -at most- N in JavaScript:
function findArrays(size, maxSum){}
Example input: findArrays(3, 2)
Example output:
[[0,0,0], [0,0,1], [0,0,2], [0,1,0], [0,1,1], [0,2,0], [1,0,0], [1,0,1], [1,1,0], [2,0,0]]
What I tried:
I came up with this algorithm:
Starting from left, add the array members
If the sum is equal to N at slot i:
If the member at the current index is equal to N, reset all the indices up to here and increment the next slot
Otherwise: reset previous slots and increment this slot
Otherwise:
Increment the first available slot
My code:
let getNextArray = (r,L,N)=>{
let sum=0, ind=0, i;
for(i=0; i<L; i++){
sum += r[i];
if(sum===N){
ind = i + (r[i]===N?1:0);
break;
}
}
r[ind]++;
for(i=0; i<ind; i++){
r[i]=0;
}
return r;
};
let findArrays=(L, N)=>{
let arrays=[],r=[],i;
for(i=0; i<L; i++){
r[i] = 0;
}
while(r[L-1]<N){
r = getNextArray(r,L,N);
arrays.push(r.slice());
}
return arrays;
}
It works for my example input, but when I call it with findArrays(5,3) it finds half (28 / 56) of the answers. Even if I made it work, I doubt it would be efficient for bigger inputs as it calculates the sum for each turn. I'm sure there is a more clever way to do it which I can't find..
Yesterday I asked a similar question which had a very good answer in terms of efficiency, but I realized I need fixed sized arrays. Apologies for the similar question but maybe it will help someone else one day :)
I could also use a method findArrays(size, sum) and iterate it with sums 1:N, unfortunately I don't know how to do that either.
You could modify trincot's solution with a small filter at the end:
function findArrays(maxSize, maxSum) {
let arr = [];
let result = []; // <--- will collect all the subarrays
function recur(maxSum) {
let k = arr.length;
result.push([...arr]);
if (k === maxSize) return;
for (let i = 0; i <= maxSum; i++) {
arr[k] = i;
recur(maxSum - i);
}
arr.length = k;
}
recur(maxSum);
return result.filter(({ length }) => length == maxSize);
}
// demo
for (let arr of findArrays(3, 2))
console.log(JSON.stringify(arr));
Here's a non-yielding version of a recursive function which will give the results you want. It figures out all possible values at the current level (0..maxSum) and then appends them to all possible results for arrays with size-1:
const findArrays = (size, maxSum) => {
let possibles = Array.from({
length: maxSum + 1
}, (_, i) => i);
if (size == 1) return possibles;
let result = [];
possibles.forEach(p => {
findArrays(size - 1, maxSum - p).forEach(a => {
result.push([p].concat(a));
});
});
return result;
}
console.log(findArrays(3, 2));

How to return the length of a contiguous subarray with specific criteria

I'm tasked with creating an array that takes another array and returns the number of contiguous subarrays for each index that fulfills the following conditions:
-The value at index i is the maximum value of the subarray
-The contiguous subarray must begin or end with i
I'm almost there but I'm missing the code to ensure that the function checks the array elements that aren't sat directly either side of i (see my code below). I think I might need some sort of recursive call that runs the if statement again while passing through the updated values of 'forward' and 'backward'. Or maybe I'm taking the wrong approach altogether.
Any ideas?
function countSubarrays(arr){
var arr = [3, 4, 1, 6, 2];
var output = [];
for (var i = 0; i < arr.length; i++){
var total = 1;
var forward = 1;
var backward = 1;
if (arr[i] >= arr[i+forward]) {
total++;
forward++;
// Some sort of recursive call here?
}
if (arr[i] >= arr[i-backward]){
total++;
backward++;
// Some sort of recursive call here?
}
output.push(total);
}
console.log(output);
}
countSubarrays();
You need to go backwards or ahead and count the items who are smaller or equal to the actual element.
function countSubarrays(array) {
var output = [];
for (let i = 0; i < array.length; i++) {
let value = array[i],
total = 1;
j = i;
while (j-- && value >= array[j]) total++;
j = i;
while (++j < array.length && value >= array[j]) total++;
output.push(total);
}
return output;
}
console.log(countSubarrays([3, 4, 1, 6, 2]));

Missing Number Algorithm Timeout Error (JavaScript)

I'm working on a Codewars Kata that is passing all tests, except it keeps timing out. Can anyone offer advice on how to optimize this? Thanks in advance!
Here is the question breakdown -
In this kata, we have an unsorted sequence of consecutive numbers from a to b, such that a < b always (remember a, is the minimum, and b the maximum value).
They were introduced an unknown amount of duplicates in this sequence and we know that there is an only missing value such that all the duplicate values and the missing value are between a and b, but never coincide with them.
Find the missing number with the duplicate numbers (duplicates should be output in a sorted array).
Let's see an example:
arr = [10,9,8,9,6,1,2,4,3,2,5,5,3]
find_dups_miss([10,9,8,9,6,1,2,4,3,2,5,5,3]) == [7,[2,3,5,9]]
And here is my solution -
function findDupsMiss(arr) {
let missingNum = [];
let newArr = [];
arr = arr.sort((a, b) => a - b);
let dup = [...new Set(arr)];
for (let y = 1; y < dup.length; y++) {
if (dup[y] - dup[y - 1] != 1) missingNum.push(dup[y] - 1)
}
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) newArr.push(arr[i])
}
}
missingNum.push(newArr);
return missingNum;
}
You could take the power of an object and the standard sorting of keys who could be used as indices of an array (positive 32 bit numbers).
This attempt has two parts
count all numbers
iterate all keys of the object with their appearances and
check if it has the missing number between the actual item and the previous item. If so, assign the missing values,
check the count and push the key if the count is greater than one.
This code completes in 7410 ms.
function findDupsMiss(arr) {
var hash = Object.create(null),
i = arr.length,
l,
v,
keys,
missing,
dupes = [],
previous, item;
while (i--) {
v = arr[i];
if (!hash[v]) {
hash[v] = 0;
}
hash[v]++;
}
keys = Object.keys(hash);
l = keys.length;
for (i = 0; i < l; i++) {
item = +keys[i];
if (previous + 1 !== item) {
missing = previous + 1;
}
if (hash[item] > 1) {
dupes.push(item);
}
previous = item;
}
return [missing, dupes];
}

leetcode 3sum assistance, how can i optimize this answer?

I have a solution that seems to pass most of the tests but is too slow. If i'm not mistaken, the complexity is O(n^3) due to the three for loops.
My idea was to start at the first three positions of the array at i, j and k, sum them, and see if it adds up to 0.
The functions objective is:
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
var threeSum = function(nums) {
var originalArray = nums
var lengthArray = nums.length
//sort array smallest to largest
nums.sort(function(a,b) {
return a-b
})
function arrayEqual(array1, array2){
var equal = false
array1.forEach((value1) => {
if(array1 === array2){
equal = true
}
})
return equal
}
var sum = 0;
var answerArray = [];
//start from first digit and add from there
for(var i = 0; i<lengthArray; i++){
for(var j = i+1; j<lengthArray; j++){
for(var k = j+1; k<lengthArray; k++){
if((nums[i]+nums[j]+nums[k] === 0)){
if(!arrayEqual(answerArray, [nums[i],nums[j],nums[k]])){
answerArray.push([nums[i],nums[j],nums[k]])
}
}
}
}
}
return Array.from(new Set(answerArray.map(JSON.stringify)), JSON.parse)
};
How can i get around having to use three for loops to make this work (aka how do i optimize this solution?)
Think this problem in this way. Choose any number from the array say k. Now you need to find two other numbers in the array which add to -k. The resulting sum of three numbers will be k + (-k) = 0.
So this problem is reduced to find two numbers in the array which adds to a given number which is O(n) using two pointers method if given array is sorted.
In a nutshell, sort the array, take each number (k) one by one (O(n)), find two other numbers with sum -k (O(n)).
Total time complexity : O(n) * O(n) = O(n2)
You can solve the problem in a runtime of O(n^2). Here is the solution using JavaScript
var threeSum = function(nums) {
var solutions = [];
var target = 0;
nums.sort(function(a, b) {
return a - b;
});
for(var i = 0; i < nums.length - 2; i++) {
if(i === 0 || (i > 0 && nums[i] !== nums[i - 1])) {
var lo = i + 1;
var hi = nums.length - 1;
var sum = - nums[i];
while(lo < hi) {
if(nums[lo] + nums[hi] === sum) {
solutions.push([nums[i],nums[lo],nums[hi]]);
while (lo < hi && nums[lo] === nums[lo + 1]) lo++;
while (lo < hi && nums[hi] == nums[hi-1]) hi--;
lo++; hi--;
}else if (nums[lo] + nums[hi] > sum) {
hi--;
}else {
lo++;
}
}
}
};
return solutions;
}

Categories