Related
I am trying to get 5 closest elements to given element, including that element, in array. For example, if we have:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17]
and I want to get 5 closest elements to 11, it should return [4, 7, 11, 12, 13]. If i pass 1 it should return [1, 2, 3, 4, 7]. If I pass 15 it should return [11, 12, 13, 15, 17].
I'm not sure what you meant;
You might've meant a code to find the element and return the five nearest elements to it by place in the array;
Or you might've meant a code to find the 5 numbers closest to a number you say.
IF you meant the first case
There are two ways to do so,
A value as a parameter
Use this code:
function closestNByValue(arr, value, n) {
let ind = arr.indexOf(value);
let finalArr = [];
if (n > arr.length) {
finalArr = Array.from(arr);
} else if (ind == -1) {
finalArr = [];
} else if (ind <= n/2 - 0.5) {
finalArr = arr.slice(0, n);
} else if (ind >= (arr.length - n/2) - 0.5) {
finalArr = arr.slice(-n);
} else if (n%2 == 0) {
finalArr = arr.slice(ind-(n/2), ind+(n/2));
} else {
finalArr = arr.slice(ind-(n/2 - 0.5), ind+(n/2 + 0.5));
}
return finalArr;
}
console.log(closestNByValue([1, 2, 3, 4, 7, 11, 12, 13, 15, 17], 11, 5))
How does it do the job?
Okay first we need to find the index of the value and save it in ind (short form of 'index') and we check multiple different situations for what the ind is so we'd be able to output the best answer as finalArr.
There are two exceptions; what if there was no such value in our array? then ind = -1 and we'd return an empty array; or what if the number of elements nearby that we seek is larger than or equal to the arr.length? then we'd return all of the arr.
But if there were no exceptions, there are three different situations for the ind; first, ind is a number that makes us have all of the finalArr values from the first of arr, second, ind be a number that makes us have all of the finalArr values from the last of arr, and third, ind being a number that we have to select half from the indexes smaller than ind and half, larger.
If it is the third way, the way we select we'd be different depending on the oddity of the numbers we want to select.
And we'll have a conditional statement for each situation and return the finalArr.
An index as a parameter
function closestNByIndex(arr, ind, n) {
let finalArr = [];
if (n > arr.length) {
finalArr = Array.from(arr);
} else if (ind == -1) {
finalArr = [];
} else if (ind <= n/2 - 0.5) {
finalArr = arr.slice(0, n);
} else if (ind >= (arr.length - n/2) - 0.5) {
finalArr = arr.slice(-n);
} else if (n%2 == 0) {
finalArr = arr.slice(ind-(n/2), ind+(n/2));
} else {
finalArr = arr.slice(ind-(n/2 - 0.5), ind+(n/2 + 0.5));
}
return finalArr;
}
console.log(closestNByIndex([1, 2, 3, 4, 7, 11, 12, 13, 15, 17], 5, 5))
Similar to the first code it works, though we have the index and we don't search for it.
The point is, if you use the function with value, it'd do the nearest 5 elements of the first value that equals the entry but such confusion is not being tolerated in the second code.
IF you meant the second case
This is a code I coded:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17];
function allDiff(arr, num1, num2) {
const finalArr = [];
const x = Math.abs(num2 - num1);
for (let y = 0; y < arr.length; y++) {
if (Math.abs(arr[y] - num1) == x) {
finalArr.push(arr[y]);
}
}
return finalArr;
}
function deleteArr(arr, delet) {
for (let x = 0; x < arr.length; x++) {
if (delet.includes(arr[x])) {
delete arr[x];
}
}
return arr;
}
function closest(arr, num) {
const map = new Map()
arr2 = Array.from(arr);
let key, value;
for (let x = 0; x < arr2.length; x++) {
key = Math.abs(arr2[x] - num);
value = allDiff(arr2, num, arr2[x]);
arr2 = deleteArr(arr2, value);
map.set(key, value);
}
return map;
}
function closestN(arr, num, n) {
const map = closest(arr, num);
const mapKeys = Array.from(map.keys());
const mapKeysSorted = mapKeys.sort(function(a, b) {
return a - b
});
let finalArr = [];
let y;
for (let i = 0; i < mapKeysSorted.length; i++) {
if (n <= 0) {
break;
}
y = map.get(mapKeysSorted[i]);
if (n < y.length) {
finalArr = finalArr.concat(y.slice(0, n + 1));
break;
}
finalArr = finalArr.concat(y);
n -= y.length;
}
return finalArr;
}
console.log(closestN(arr, 11, 5));
It might be a little too long, but I have programmed it as you can give it any array (arr) with integer values, an integer (num) that you'd like it to be the base and another integer (n) for the number of the size of the output array, 5 in this case.
Explaining the code
The function closest would return a map of (the difference between the numbers, a list of the numbers in the arr that differs the number equal to their key).
The main function, closestN, calls the closest function and saves the map in the map variable.
Then it sorts the keys of the map in mapKeysSorted.
Now, a for loop loops through the mapKeySorted array and pushes new elements to the finalArr until the size of the finalArr reaches the number of elements we seek.
The main function is the closestN.
Here's a way to get to your goal:
To start, first thing to do is finding the index of the wanted number in the array. Example index of 1 in your array arr is 0. The index will help in extracting the numbers later on. The method findIndex will help us in finding the index.
Then, we need to find the position at which will start extaracting the closest numbers (in terms of position not value). As seen from the desired output you have provided, usually you want the returned array to be in the following structure:
output: [
2 nearest numbers (from N left),
the wanted number,
2 nearest numbers (from N right)
]
This can get tricky so we should make sure to deal with some edge case like when the wanted element is sitting at position 0.
Extract the numbers and return them as an array as described by your desired output. The use of slice method will come in handy here which allow us to extract the numbers just as we need.
Here's a live demo demonstrating solution:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17],
/** a function that returns an array containing the "5" (depending on "arr" length that could be less) nearest numbers (in terms of position) in "arr" array to the supplied number "n" */
findClosestNumbers = n => {
/** make sure we don't exceed the array length */
const toTake = 5 > arr.length ? arr.length : 5,
/** find the index of the wanted nulber "n", if "-1" is returned then "n" cannot be found ion the array "arr" */
idx = arr.findIndex(el => n == el),
/**
* from where we should start returning the nearest numbers (the position of the first number to extract from "arr"
* the below condition help deal with some edge cases like when "n" is the last element in "arr"
*/
startIdx = idx + toTake / 2 > arr.length ?
arr.length - 5 :
(idx - 2 >= 0 ?
idx - 2 :
0);
/** return the nearest numbers or return an empty array "[]" if the number "n" is not found on the array "arr" */
return idx == -1 ? [] : arr.slice(startIdx, startIdx + 5);
};
/** run for various scenarios */
console.log('For 1 =>', findClosestNumbers(1));
console.log('For 11 =>', findClosestNumbers(11));
console.log('For 15 =>', findClosestNumbers(15));
console.log('For 17 =>', findClosestNumbers(17));
.as-console-wrapper {
max-height: 100%!important;
}
The demo above is meant to help you understand how things could work and it is not the only way to get to your goal. Also, because I kept it as simple as possible, the above demo is wide open for improvements.
I need to create a function which finds the two numbers with the largest difference between them and returns their indices as an array of two elements - [ lowest, biggest ].
Notice: the bigger number must be to the right from lowest. If we have no difference between the numbers, the function must return [].
function getProfit(arr) {
let result = [];
let sortedArr = arr.sort();
let min = sortedArr.indexOf(Math.min(...sortedArr));
let max = sortedArr.indexOf(Math.max(...sortedArr));
if(max > min) {
result.push(min);
result.push(max);
return result;
} else {
return [];
}
}
console.log(getProfit([13, 6, 3, 4, 10, 2, 3], [2, 4]));
You need to iterate through the list with two pointers (indexes) left and right as described below:
you will accomplish your solution with time complexity of O(n).
function getProfit(arr) {
let result = [0,0];
for(let l=0,r=0; l<arr.length-1 && r<arr.length-1;r++){
if(arr[l] > arr[r]){
l++;
}else if(arr[r]-arr[l]> arr[result[1]]-arr[result[0]]){
result[0] = l;
result[1] = r;
}
}
return (result[1] === 0) ? [] : result;
}
console.log(getProfit([13, 6, 3, 4, 10, 2, 3]));
I have 2 questions, how can I get value instead of value inside array and how can I make this code shorter and declarative.
arr = [16, 4, 11, 20, 2]
arrP = [7, 4, 11, 3, 41]
arrTest = [2, 4, 0, 100, 4, 7, 2602, 36]
function findOutlier(arr) {
const isPair = (num) => num % 2 === 0
countEven = 0
countOdd = 0
arr1 = []
arr2 = []
const result = arr.filter((ele, i) => {
if (isPair(ele)) {
countEven++
arr1.push(ele)
} else {
countOdd++
arr2.push(ele)
}
})
return countEven > countOdd ? arr2 : arr1
}
console.log(findOutlier(arrTest))
Filtering twice may be more readable.
even = arr.filter((x) => x % 2 == 0);
odd = arr.filter((x) => x % 2 == 1);
if (even.length > odd.length) {
return even;
} else {
return odd;
}
If you're looking to do this with one loop, consider using the array reduce method to put each number into an even or odd bucket, and then compare the length of those buckets in your return:
function findOutlier(arr) {
const sorted = arr.reduce((acc, el) => {
acc[el % 2].push(el);
return acc;
},{ 0: [], 1: [] })
return sorted[0].length > sorted[1].length ? sorted[1] : sorted[0];
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(findOutlier(arr));
Note that this does not handle when the arrays are the same length gracefully (right now it'll just return the odd array).
You could take an object with the wanted part for collecting and add a short circuit if one of the types has a count of one and the others have a count greater than one.
const
isPair = num => num % 2 === 0,
findOutlier = array => {
count = { true: [], false: [] };
for (const value of array) {
count[isPair(value)].push(value);
if (count.true.length === 1 && count.false.length > 1) return count.true[0];
if (count.false.length === 1 && count.true.length > 1) return count.false[0];
}
};
console.log(...[[16, 4, 11, 20, 2], [7, 4, 11, 3, 41], [2, 4, 0, 100, 4, 7, 2602, 36]].map(findOutlier));
Here is an solution that selects the even or odd array based on the modulo result.
function findOutlier(integers) {
const even = [], odd = [], modulos = [even, odd];
for (const integer of integers) {
modulos[Math.abs(integer % 2)].push(integer);
}
return even.length > odd.length ? odd : even;
}
console.log(findOutlier([2, 4, 0, 100, 4, 7, 2602, 36]));
You unfortunately do need Math.abs() to handle negative values, because -3 % 2 == -1.
See: JavaScript % (modulo) gives a negative result for negative numbers
However the name findOutlier lets me assume there is only a single outlier within the provided list. If this is the case you can optimize the algorithm.
function findOutlier(integers) {
// With less than 3 integers there can be no outlier.
if (integers.length < 3) return;
const isEven = (integer) => integer % 2 == 0;
const isOdd = (integer) => !isEven(integer);
// Determine the outlire based on the first 3 elements.
// If there are 0 or 1 integers even, the outlire is even.
// if there are 2 or 3 integers even, the outlier is odd.
const outlier = integers.slice(0, 3).filter(isEven).length < 2
? isEven
: isOdd;
return integers.find(outlier);
}
console.log(findOutlier([2, 4, 0, 100, 4, 7, 2602, 36]));
You can do this without creating intermediate arrays by simply comparing each element to its neighbors and returning that element if it is different to both, or undefined if no outliers are found. This returns in the same iteration in which the outlier is first encountered, and returns the value itself and not an array.
function findOutlier(array) {
const
len = array.length,
isEven = (n) => n % 2 === 0;
for (const [i, value] of array.entries()) {
let
prev = array[(i-1+len)%len], // loop around if < 0 (first element)
next = array[(i+1)%len]; // loop around if >= length (last element)
if (isEven(value) !== isEven(prev) && isEven(value) !== isEven(next)) {
return value;
}
}
return undefined;
}
const arrays = [[16, 4, 11, 20, 2], [7, 4, 11, 3, 41], [2, 4, 0, 100, 4, 7, 2602, 36]]
console.log(...arrays.map(findOutlier));
Now that OP clarified the requirements (at least in a comment) this allows a different approach:
function findOutlier(array) {
let odd = undefined, even = undefined;
for (let i of array) {
let isEven = i % 2 == 0;
if (odd !== undefined && even !== undefined)
return isEven ? odd : even;
if (isEven) even = i;
else odd = i;
}
if (odd !== undefined && even !== undefined)
return array[array.length-1];
}
console.log(findOutlier([2,4,6,8,10,5]))
The algorithm will iterate the array, and store the lastest found odd and even numbers, respectively.
If we discovered both an odd and an even number already, with the current number we can decide, which of them is the outlier: If the current number is even, it's at least the second even number we found. Thus, the found odd number must be the outlier. The same applies vice versa if the current number is odd. The special case, if the outlier is the last element of the array, is checked with an additional condition after the loop.
If all numbers are odd or even (ie there is no outlier) this function will return undefined. This algorithm does not throw an error, if the preconditions are not met, ie if there is more than one outlier.
My goal here is to find the prime numbers:
let arr = [2, 3, 4, 6, 9, 10, 11, 15];
let ret = [];
arr.filter((z, ind) => {
if (ind > 0) {
ret.every(x => {
!Number.isInteger(z / x) ? ret.push(z) : false;
});
} else {
ret.push(z);
}
});
console.log(ret); // should be: [2,3,11]
It works for even numbers, but it doesn't work for the odd.
Fixed your code:
let arr = [2,3,4,6,9,10,11,15]
let ret = [];
arr.filter((z, ind) => {
if(ind > 0){
if(ret.every( x => !Number.isInteger(z/x)) ){
ret.push(z)
}
} else { ret.push(z) }
})
console.log(ret)
The Array.filter() method returns an array, so no need to generate the array by pushing the elements to an external array.
The prime check is easier with a for loop. Check that the number doesn't produce an integer if divided by all the numbers between 2 and half its size (rounded down). We need to check all half way, because every number that is greater than half the number we are checking, would produce a result that is less than 2, and 2 is the smallest integer divisor of a number.
const arr = [2, 3, 4, 6, 9, 10, 11, 15];
const isPrime = num => {
if(num < 4) return true; // 1, 2, 3 are prime numbers
const div = Math.floor(num / 2); // the max number to use as divider
for(let i = 2; i <= div; i++) {
if(Number.isInteger(num / i)) return false; // if the result is an integer, it's not a prime number
}
return true; // it's a prime number
};
const result = arr.filter(isPrime);
console.log(result); // should be: [2,3,11]
Per Codefighters:
Note: Write a solution with O(n) time complexity and O(1) additional
space complexity, since this is what you would be asked to do during a
real interview.
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, 3, 3, 1, 5, 2], the output should be firstDuplicate(a) =
3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3
has a smaller index than than second occurrence of 2 does, so the
answer is 3.
For a = [2, 4, 3, 5, 1], the output should be firstDuplicate(a) = -1.
So here is what I came up with. It works but fails on the final test because it ran over 4000ms. I'm at a loss as to what else I can do. Any Ideas to improve speed?
function firstDuplicate(a) {
var test = [],
lowest = undefined;
for (var i=0; i<a.length; i++) {
if (test.indexOf(a[i]) > -1) {
lowest = lowest || i;
if (i < lowest) {
lowest = i;
}
}
else {
test.push(a[i]);
}
}
return lowest ? a[lowest] : -1;
}
Here was my second attempt but still failing on the last test...
function firstDuplicate(a) {
var low = undefined,
last = -1;
for (var i=0; i<a.length; i++) {
last = a.lastIndexOf(a[i])
if (last > i && (low === undefined || last < low)) {
low = last;
}
}
return low !== undefined ? a[low] : -1;
}
The requirements give a clue of how to solve this. The set of numbers contained in the array must match the following critera:
only numbers in the range from 1 to a.length
In other words, only positive numbers that are less than or equal to the length of the array. If the array contains ten numbers, none of them will be greater than 10.
With that insight, we have a means of keeping track of numbers that we have already seen. We can treat the numbers themselves as indexes into the array, modify the element at that index (in this case by making it negative) and if we run into the same number and the element at that index is less than zero, then we know we have seen it.
console.clear()
const test1 = [2, 3, 3, 1, 5, 2]
const test2 = [2, 4, 3, 5, 1]
function firstDuplicate(a) {
for (let i of a) {
let posi = Math.abs(i) - 1
if (a[posi] < 0) return posi + 1
a[posi] = a[posi] * -1
}
return -1
}
console.log(firstDuplicate(test1))
console.log(firstDuplicate(test2))
console.log(firstDuplicate([2,2]))
console.log(firstDuplicate([2,3,3]))
console.log(firstDuplicate([3,3,3]))
Original Incorrect Answer
Keep track of what numbers have already been seen and return the first one that has been seen before.
console.clear()
const test1 = [2, 3, 3, 1, 5, 2]
const test2 = [2, 4, 3, 5, 1]
function firstDuplicate(a){
const seen = {}
for (let v of a){
if (seen[v]) return v
seen[v] = v
}
return -1
}
console.log(firstDuplicate(test1))
console.log(firstDuplicate(test2))
As pointed out in the comments, however, this answer takes O(n) additional space, not O(1) additional space.
We will take advantage of the fact that the array a contains only numbers in the range from 1 to a.length, to remember that a value has been seen by reversing the sign of whatever is in that position in the array.
function lowestDuplicate(arr) {
for (let i = 0; i < arr.length; i++) {
const val = Math.abs(arr[i]);
if (arr[val - 1] < 0) return val;
arr[val - 1] = -arr[val - 1];
}
return -1;
}
console.log(lowestDuplicate([1, 2, 3, 4, 3, 2, 1]));
console.log(lowestDuplicate([1, 2, 3, 4, 5]));
console.log(lowestDuplicate([5, 4, 3, 2, 2]));
console.log(lowestDuplicate([2, 2]));
console.log(lowestDuplicate([2, 3, 3]));
console.log(lowestDuplicate([3, 3, 3]));
console.log(lowestDuplicate([2, 3, 3, 1, 5, 2]));
Python 3 version that passes the tests.
def firstDuplicate(a):
oldies={}
notfound=True
for i in range(len(a)):
try:
if oldies[a[i]]==a[i]:
notfound=False
return a[i]
except:
oldies[a[i]]=a[i]
if notfound:
return -1
You are iterating n times in both examples.
What if the array length was 200,000,000 and the first duplicate was found at index 3? The loop is still running 200,000,000 times unnecessarily.
So the idea is to break out of the loop once you find the first duplicate.
you can use break or just return.
A simple solution in JS. As the question title focus, you just need to find the first duplicate of the number you already traversed. So i guess this will do:
function solution(a) {
let duplicateArray = []
for(let i=0;i<a.length;i++){
if(duplicateArray.includes(a[i])){
return a[i];
}
duplicateArray.push(a[i])
}return -1;}
Hope this helps.