Related
The task:
You are given 3 sorted arrays. You should find the smallest number
that is common in all 3 arrays and return it. If such a number doesn't
exist, return -1
My approach:
Use early exit: If one of the array is empty, then we know there won't be a common number in all arrays
Create pointer that points to the first element of the corresponding array
In the outer loop, loop through all elements of the first array. If any of the pointer over reaches the end of the array, then break the loop because we have reached the end and haven't found a common number
In the first inner loop check the second array for the element the pointer of the first array is pointing to
If you found it then set a flag. Otherwise remember the running index to the second pointer so we can continue at this element in the next iteration
If the flag is set, then loop through the second inner loop. In here it's analogous to the first inner loop: Search for the current element in the 3rd array.
If you find it, then immediately return the value. If not go to the next element until you find an element bigger than the current one
Increment the pointer of the first array
Do this until you reach either one of the array
My Solution:
let findLeastCommonNumber = function(a, b, c) {
if (a.length === 0 || b.length === 0 || c.length === 0) {
return -1;
}
let aPointer = 0;
let bPointer = 0;
let cPointer = 0;
while (aPointer < a.length ||
bPointer < b.length ||
cPointer < c.length) {
const aValue = a[aPointer];
let bFound = false;
for (let i = bPointer; i < b.length; i++) {
if (b[i] === aValue) {
bPointer = i;
bFound = true;
break;
}
if (b[i] > aValue) {
bPointer = i;
break;
}
}
if (bFound) {
for (let i = cPointer; i < c.length; i++) {
if (c[i] === aValue) {
return a[aPointer];
}
if (c[i] > aValue) {
cPointer = i;
break;
}
}
}
aPointer++;
}
return -1;
};
Sample solution:
let find_least_common_number = function(a, b, c) {
let i = 0;
let j = 0;
let k = 0;
while (i < a.length
&& j < b.length
&& k < c.length) {
// Finding the smallest common number
if (a[i] === b[j]
&& b[j] === c[k]) {
return a[i];
}
// Let's increment the iterator
// for the smallest value.
if (a[i] <= b[j]
&& a[i] <= c[k]) {
i++;
} else if (b[j] <= a[i]
&& b[j] <= c[k]) {
j++;
} else if (c[k] <= a[i]
&& c[k] <= b[j]) {
k++;
}
}
return -1;
};
I like the fact that the sample solution has less nesting. But the sample solution doesn't take advantage of an early exit and I think my solution is more scalable. Let's say the requirements changes, and 27 arrays more are now included. In my solution, I'd just copy the inner loops and change the pointer names only. I don't need to touch existing code. In the sample solution, however, I'd have touch every line of code that refers to one of the arrays and I would add the new arrays there. What do you think?
You could a completely dynamic approach for an infinite (sort of) count of arrays.
function findLeastCommonNumber(...array) {
var indices = array.map(_ => 0),
smallest = Math.max(...array.map((a, i) => a[indices[i]])),
next;
while (indices.every((i, j) => i < array[j].length)) {
next = smallest;
array.forEach((a, i) => {
while (indices[i] < a.length && a[indices[i]] < smallest)
next = Math.max(next, a[++indices[i]]);
});
if (array.every((a, i) => a[indices[i]] === smallest)) return smallest;
smallest = next;
}
return -1;
}
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7], [8, 9, 10], [1, 2, 3, 5, 6, 7, 9]));
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7, 9, 10], [1, 2, 3, 5, 6, 7, 9, 10], [4, 6, 7, 8, 9, 10, 11, 12]));
console.log(findLeastCommonNumber([1, 5, 6, 7, 8, 10], [5, 6, 9, 10], [1, 2, 3, 4, 5, 6, 9, 10]));
For the more readable solution, you can use this:
const findLeastCommonNumber = function() {
const total = [].concat(...arguments).sort((a,b) => a > b ? 1 : -1);
let index = 0;
let commonNumber = -1;
while(total.length - 2 > index && commonNumber === -1){
if(total[index] === total[index + 1] && total[index] === total[index + 2]){
commonNumber = total[index];
}
index++;
}
return commonNumber;
};
console.log(findLeastCommonNumber([1,5,6,7,8,10],[5,6,9,10],[1,2,3,4,5,6,9,10]));
An alternative solution - Take the 1st array, and convert the other arrays to Sets. Now use Array.find() on the 1st array, and check with Array.every() if the current number is found in all sets.
const findLeastCommonNumber = (main, ...array) => {
const sets = array.map(o => new Set(o));
const common = main.find(n => sets.every(s => s.has(n)));
return common === undefined ? -1 : common;
};
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7], [8, 9, 10], [1, 2, 3, 5, 6, 7, 9]));
console.log(findLeastCommonNumber([1, 2, 3, 4, 5, 7, 9, 10], [1, 2, 3, 5, 6, 7, 9, 10], [4, 6, 7, 8, 9, 10, 11, 12]));
console.log(findLeastCommonNumber([1, 5, 6, 7, 8, 10], [5, 6, 9, 10], [1, 2, 3, 4, 5, 6, 9, 10]));
The arrays are sorted in ascending order. We will use three
iterators simultaneously to traverse each of the arrays. We can
start traversing each array from the 0^{th}index, which always has
the smallest value.
If the values pointed to by the three iterators are equal, that is
the solution. Since the arrays are sorted in ascending order, that
value must be the smallest value present in all of the arrays.
Otherwise, we see which of the three iterators points to the
smallest value and increment that iterator so that it points to the
next index.
If any of the three iterators reaches the end of the array before
we find the common number, we return -1.
let findLeastCommonNumber = function(arr1, arr2, arr3) {
// Initialize starting indexes for arr1, arr2 and arr3
let i = 0;
let j = 0;
let k = 0;
// Iterate through three arrays
while (i < arr1.length && j < arr2.length && k < arr3.length) {
// Finding the smallest common number
if (arr1[i] === arr2[j] && arr2[j] === arr3[k]) {
return arr1[i];
}
// Let's increment the iterator
// for the smallest value.
if (arr1[i] <= arr2[j] && arr1[i] <= arr3[k]) {
i++;
}
else if (arr2[j] <= arr1[i] && arr2[j] <= arr3[k]) {
j++;
}
else if (arr3[k] <= arr1[i] && arr3[k] <= arr2[j]) {
k++;
}
}
return -1;
};
let v1 = [6, 7, 10, 25, 30, 63, 64];
let v2 = [0, 4, 5, 6, 7, 8, 50];
let v3 = [1, 6, 10, 14];
console.log("Least Common Number: " + findLeastCommonNumber(v1, v2, v3));
i have 2 rows that i need to check in java script if they are symmetrical
row 1 [2, 7, 9, 9, 7, 2] row 2 [5 7 3 3 7 5] how would you do it ?
var r = [[5, 7, 3, 3, 7, 5], [2, 7, 9, 9, 7, 2]];
function isSymmetric(r) {
// convert to object
var rel = {}
for (var i = 0; i < r.length; i++) {
if (!(r[i][0] in rel)) rel[r[i][0]] = {};
rel[r[i][0]][r[i][1]] = true;
}
// Test to see if opposite relation is in object
for (var a in rel) {
for (var b in rel[a]) {
if (!rel[b] || !rel[b][a]) return false;
}
}
return true;
}
console.log(isSymmetric(r));
You could do something like this:
let isSymmetric = arr => {
for(var i=0; i < arr.length; i++) {
if(arr[i] !== arr[arr.length - (i+1)])
return false
}
return true
}
console.log(isSymmetric([5, 7, 3, 3, 7, 5]))
console.log(isSymmetric([1, 7, 9, 9, 7, 2]))
The idea is to loop through the array and for each index compare with its "sibling" from the right side. If one is not the same them return false.
You can start from 0th index and compare the value with its symmetric pair (length - 1 - i), and if they are not same then return false. You should stop at the middle length / 2:
let values = [
[5, 7, 3, 3, 7, 5],
[2, 7, 9, 1, 9, 7, 2],
[5, 7, 3, 3, 7, 1]
];
function isSymmetric(arr) {
for (let i = 0; i < arr.length / 2; i++) {
if (arr[i] !== arr[arr.length - 1 - i]) {
return false;
}
}
return true;
}
values.forEach(v =>
console.log(isSymmetric(v))
);
Use lodash.
var row = [2, 7, 9, 9, 7, 2];
var halves = _.chunk(row, _.ceil(row.length / 2));
var result = _.isEqual(halves[0], _.reverse(halves[1]));
I need to find the index of the first duplicated number in an array and assign it to an empty variable using only for loop
Thanks in advance
i have tried many logical operators.
var findIndex;
var arrWithNumbers = [2, 4, 5, 2, 6, 5, 1, 2, 4, 8]; //-----> it should give result console.log(findIndex) // 0
var arrWithNumbers = [3, 4, 5, 2, 6, 5, 1, 2, 4, 8]; //-----> it should give result console.log(findIndex) // 1
var arrWithNumbers = [2, 4, 5, 2, 6, 5, 1, 2, 4, 8];
var firstIndex = null;
for (var i = 0; i < arrWithNumbers.length; i++) {
if (arrWithNumbers[i] === i) {
firstIndex = arrWithNumbers.indexOf(i);
break;
}
}
console.log(firstIndex);
what I expect:
var arrWithNumbers = [2, 4, 5, 2, 6, 5, 1, 2, 4, 8]; //-----> it should give result console.log(findIndex) // 0
var arrWithNumbers = [3, 4, 5, 2, 6, 5, 1, 2, 4, 8]; //-----> it should give result console.log(findIndex) // 1
//what i have
var arrWithNumbers = [2, 4, 5, 2, 6, 5, 1, 2, 4, 8];
var firstIndex = null;
for (var i = 0; i < arrWithNumbers.length; i++) {
if (arrWithNumbers[i] === i) {
firstIndex = arrWithNumbers.indexOf(i);
break;
}
}
console.log(firstIndex); // 2
One option you have is to have a variable that contains all the count of the number, you can do this by using reduce
var arrWithNumbers = [2, 4, 5, 2, 6, 5, 1, 2, 4, 8];
var firstIndex = null;
var numberCount = arrWithNumbers.reduce((c, v) => (c[v] = (c[v] || 0) + 1, c), {});
for (var i = 0; i < arrWithNumbers.length; i++) {
if (numberCount[arrWithNumbers[i]] > 1) {
firstIndex = i;
break;
}
}
console.log(firstIndex);
Another option is using lastIndexOf. If the current index is not the same as the lastIndexOf value, means that it has duplicate and break the loop.
var arrWithNumbers = [3, 2, 4, 5, 2, 6, 5, 1, 2, 4, 8];
var firstIndex = null;
for (var i = 0; i < arrWithNumbers.length; i++) {
if (i !== arrWithNumbers.lastIndexOf(arrWithNumbers[i])) {
firstIndex = i;
break;
}
}
console.log(firstIndex);
You could take a hash table for visited values and store their indices. Then you need only the check if the hash property is set and return the index.
This approach works with a single loop and exits early on the first found same value.
function findIndex(array) {
var indices = Object.create(null),
i, value;
for (i = 0; i < array.length; i++) {
value = array[i];
if (value in indices) return indices[value];
indices[value] = i;
}
}
console.log(findIndex([2, 4, 5, 2, 6, 5, 1, 2, 4, 8])); // 0
console.log(findIndex([3, 4, 5, 2, 6, 5, 1, 2, 4, 8])); // 2
You can use a nested for loop, to check all values after index i in your array :
var arrWithNumbers = [2, 4, 5, 2, 6, 5, 1, 2, 4, 8];
var firstIndex = null;
for (var i = 0; i < arrWithNumbers.length; i++) {
value_i = arrWithNumbers[i]
// loop through the next items of the array
for (var j = i+1 ; j < arrWithNumbers.length; j++) {
if (value_i == arrWithNumbers[j]) {
firstIndex = i;
break;
}
}
if (firstIndex !== null) {
// we found our firstIndex, quit the main loop
break;
}
}
console.log(firstIndex)
I am taking an excercise on codewars:
Given a list of integers and a single sum value, return the first two
values (parse from the left please) in order of appearance that add up
to form the sum.
Example:
sum_pairs([10, 5, 2, 3, 7, 5], 10)
# ^-----------^ 5 + 5 = 10, indices: 1, 5
# ^--^ 3 + 7 = 10, indices: 3, 4 *
# * entire pair is earlier, and therefore is the correct answer
== [3, 7]
What do you think entire pair is earlier means? IMO if the sum of it's indexes is smallest. Now based on this assumption I made my solution and one test fails:
var sum_pairs=function(ints, s){
let i = 0;
let pair = [0, 0];
let ind = [100, 100]
let found = false;
function loop(i) {
if (i > ints.length) return pair;
ints.slice(i).forEach((curr, idx) => {
ints.slice(i+1).some((num, i) => {
let sum = curr + num;
let prevIndicies = ind[0] + ind[1];
if(sum === s && prevIndicies > idx + i) {
ind = [idx, i];
pair = [curr, num];
found = true;
return true;
}
})
})
i += 1;
loop(i)
}
loop(0)
if (found) {
return pair
}
return undefined;
}
console.log(sum_pairs([1,4,8,7,3,15], 8))
Test returns error that [1, 7] is expected.
I'm pretty sure what it means is they want the second element to be as leftward in the list as possible. For example, for
l5= [10, 5, 2, 3, 7, 5];
when trying to find a sum of 10, the desired output is
[3, 7]
[10, 5, 2, 3, 7, 5];
^ ^
instead of
[5, 5]
[10, 5, 2, 3, 7, 5];
^ ^
because the last element in [3, 7], the 7, came before the second 5.
This code seems to pass all test cases - iterate in a triangular fashion, starting at indicies [0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3], ...:
const sum_pairs = function(ints, s){
const { length } = ints;
for (let i = 1; i < length; i++) {
for (let j = 0; j < i; j++) {
if (ints[i] + ints[j] === s) return [ints[j], ints[i]];
}
}
}
const sum_pairs=function(ints, s){
const { length } = ints;
for (let i = 1; i < length; i++) {
for (let j = 0; j < i; j++) {
if (ints[i] + ints[j] === s) return [ints[j], ints[i]];
}
}
}
l1= [1, 4, 8, 7, 3, 15];
l2= [1, -2, 3, 0, -6, 1];
l3= [20, -13, 40];
l4= [1, 2, 3, 4, 1, 0];
l5= [10, 5, 2, 3, 7, 5];
l6= [4, -2, 3, 3, 4];
l7= [0, 2, 0];
l8= [5, 9, 13, -3];
console.log(sum_pairs(l1, 8))
console.log(sum_pairs(l2, -6))
console.log(sum_pairs(l3, -7))
console.log(sum_pairs(l4, 2))
console.log(sum_pairs(l5, 10))
console.log(sum_pairs(l6, 8))
console.log(sum_pairs(l7, 0))
console.log(sum_pairs(l8, 10))
It means that you go from left to right and take the first matching pair, and since 7 is the first element that creats a pair (going from the left) 3 and 7 is the first pair.
I would solve it a bit easier:
function sum_pairs(arr, target) {
let old = [];
let result = [];
arr.some((el) => {
let found = old.find((oldEl) => oldEl + el === target);
if (found) return result = [found, el];
old.push(el);
})
return result;
}
sum_pairs([10, 5, 2, 3, 7, 5], 10);
Edit: an explaination. I loop over all elements in the array searching for a match i all the elements I have passed. If I find a match I remember it and break out of the loop by returning a "truthy" value. (That is just how .some() works.) Finally if I have not found a match I add the element to my list of old elements and go on to the next.
function sum_pair(arr,sum){
let result = [];
arr.forEach((i, j)=>{
if(i+arr[j+1]===sum){
console.log(i,arr[j+1], i+arr[j+1])
}
})
}
sum_pair([0, 3, 7, 0, 5, 5],10)
What is an efficient way of looping through two arrays to produce an alternating output? In JavaScript.
If I have two arrays like this:
var oddNumbers = [1, 3, 5, 7, 9]
var evenNumbers = [2, 4, 6, 8, 10, 12, 14]
NB: The arrays may not be the same length
How can I get the following output?
Output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14
I would have thought this would work:
if (oddNumber.length > evenNumbers.length) {
var large = oddNumbers;
} else {
var large = evenNumbers;
}
for(var i = 0; i < large.length; i++){
if (evenNumbers.length >= i && oddNumbers.length >= i) {
console.log(oddNumbers[i] + ", " + evenNumbers[0]);
} elseif (evenNumbers.length >= i) {
console.log(evenNumbers[0]);
} else {
console.log(oddNumbers[0]);
}
}
But it's pretty messy, any better way of approaching this?
NOTE: These may not necessarily be in a numerical order, or in fact numbers
I would rather do it as follows if you just want to output them:
var oddNumbers = [1, 3, 5, 7, 9];
var evenNumbers = [2, 4, 6, 8, 10, 12, 14];
for (var i=0, j=0; i < oddNumbers.length || j < evenNumbers.length;) {
if (i < oddNumbers.length) {
console.log(oddNumbers[i++]);
}
if (j < evenNumbers.length) {
console.log(evenNumbers[j++]);
}
}
If you want to get the merge result as another array you can replace console.log with result.push to push result values on an array named result as follows:
var oddNumbers = [1, 3, 5, 7, 9];
var evenNumbers = [2, 4, 6, 8, 10, 12, 14];
var result = [];
for (var i=0, j=0; i < oddNumbers.length || j < evenNumbers.length;) {
if (i < oddNumbers.length) {
result.push(oddNumbers[i++]);
}
if (j < evenNumbers.length) {
result.push(evenNumbers[j++]);
}
}
console.log(result);
This way you iterate both arrays as long as one of them has an element that we haven't visited yet and also prevents iterating over the same index of same array twice. Please note that I used increment in if blocks to save 2 lines of code. You can also move them to the for loop since they won't break if statements.
var oddNumbers = [1, 3, 5, 7, 9];
var evenNumbers = [2, 4, 6, 8, 10, 12, 14];
var oLength = oddNumbers.length;
var eLength = evenNumbers.length;
var n = oLength > eLength ? oLength : eLength;
var rez=[];
for(i=0;i<n;i++){
if (i< oLength) rez.push(oddNumbers[i])
if (i<eLength) rez.push(evenNumbers[i])
}
console.log(rez);
var odd = ["A", "C","E","G"];
var even = ["B","D","F"];
var rez=[];
for(i=0;i<(odd.length > even.length ? odd.length : even.length);i++){
if (i< odd.length) rez.push(odd[i])
if (i<even.length) rez.push(even[i])
}
console.log(rez);
The following function accepts two arrays and returns their interleaved values as a new array:
function interleaveArrays(a, b) {
var array = [],
limit = a.length >= b.length ? a.length : b.length;
index = 0;
while (index < limit) {
a[index] && array.push(a[index]);
b[index] && array.push(b[index]);
index += 1;
}
return array;
}
Calling the function like so:
var oddNumbers = [1, 3, 5, 7, 9],
evenNumbers = [2, 4, 6, 8, 10, 12, 14];
console.log(interleaveArrays(oddNumbers, evenNumbers));
Yields:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14 ]
You can then output this in your preferred manner; e.g:
var interleaved = interleaveArrays(oddNumbers, evenNumbers);
// as a loop
interleaved.forEach(function (n) {
console.log(n);
})
// or as a string
console.log(interleaved.join(', '));
// etc.
Hope this helps :)
I'd do something like this.
large = (oddNumber.length >= evenNumbers.length) ? oddNumbers : evenNumbers;
small = (oddNumber.length < evenNumbers.length) ? oddNumbers : evenNumbers;
for(var i = 0; i < large.length; i++){
if(small.length <= i + 1){
console.log(small[i] + ", "+ large[i]);
}
else {
console.log(large[i]);
}
}
A long-hand example of how it can be done. The code can be shrunk for a final solution. The basic principle I'm using is to even out the lengths to take care of the alternating then tag on the tail
var oddNumbers = [1, 3, 5, 7, 9];
var evenNumbers = [2, 4, 6, 8, 10, 12, 14];
var oLength = oddNumbers.length;
var eLength = evenNumbers.length;
var oTemp, eTemp, remainder;
if(oLength > eLength) {
eTemp = evenNumbers;
oTemp = oddNumbers.slice(0, eLength);
remainder = oddNumbers.slice(eLength);
} else if (eLength > oLength) {
eTemp = evenNumbers.slice(0, oLength);
oTemp = oddNumbers;
remainder = evenNumbers.slice(oLength);
} else {
eTemp = evenNumbers;
oTemp = oddNumbers;
remainder = [];
}
var final = [];
for(var i=0; i < eTemp.length; i++) {
final.push(oTemp[i]);
final.push(eTemp[i]);
}
final = final.concat(remainder);
alert(final);
I would simply merge the two array and sort it
var oddNumbers = [1, 3, 5, 7, 9];
var evenNumbers = [2, 4, 6, 8, 10, 12, 14];
var mergedArr=oddNumbers.concat(evenNumbers );
console.log(mergedArr.sort(function(a,b){return a-b;}));
See No loop.. No hassle. Very Simple
There will be an extra , on the screen. Add an if statement if you don't want that
for(var i = 0; i < large.length; i++){
if(i<evenNumbers.length)
console.log(evenNumbers[i]+",");
if(i<oddNumber.length)
console.log(evenNumbers[i]+",");
}
try this it will work always either number Array or String Array:
var oddNumber = [1, 3, 5, 7, 9]
var evenNumber = [2, 4, 6, 8, 10, 12, 14]
var margedNumbers = oddNumber.concat(evenNumber);
console.log("before: "+margedNumbers);
margedNumbers.sort(function(a, b){return a-b})
console.log("after: "+margedNumbers)
My solution
var oddNumbers = [1, 3, 5, 7, 9]
var evenNumbers = [2, 4, 6, 8, 10, 12, 14]
var extraElements = (oddNumbers.length > evenNumbers.length) ? oddNumbers.slice(evenNumbers.length) : evenNumbers.slice(oddNumbers.length);
var finalArr = [];
var small = (oddNumbers.length < evenNumbers.length) ? oddNumbers : evenNumbers;
small.forEach((each, index) => {
// merge elements in desired order
finalArr.push(oddNumbers[index]);
finalArr.push(evenNumbers[index]);
})
finalArr = finalArr.concat(extraElements);
alert(finalArr);
Extract the extra elements which makes both array of same length. Then, in a simple iteration, push elements from both array with same index.