I was trying to solve some of the programming challenges at "free code camp" website, The problem was to find the symmetric difference between multiple arrays and returning an array of the symmetric difference of the provided arrays.
for example the following arrays:
[1, 2, 5], [2, 3, 5], [3, 4, 5]
should return [ 1, 4, 5 ]
so that's what I came up with:
function sym() {
var final = [];
var current_array = [];
for (var i = 0; i < arguments.length; i++) {
current_array = arguments[i];
//ensures duplicates inside each array are removed first
current_array = current_array.filter(function (element, index) {
return current_array.indexOf(element) == index;
});
for (var j = 0, end = current_array.length; j < end; j++) {
if(final.indexOf(current_array[j]) < 0)
final.push(current_array[j]);
else
// for some reason "splice" isn't working properly..
// final.splice(final.indexOf(current_array[j], 1));
delete final[final.indexOf(current_array[j])];
}
}
var final_2 = [];
// Removing the empty slots caused by the "delete" keyword usage
for (var m = 0; m < final.length; m++) {
if(typeof final[m] !== 'undefined')
final_2.push(final[m]);
}
return final_2;
}
in the previous logic I created an array called final that is supposed to hold all of the elements that only exist once in all of the passed arrays, firstly I loop over the arguments parameter which represents here the arrays and for each array I loop over its elements and check if that element exists in the final array or not. If it exists I remove it from the final array, else I push it to the array.
The problem here is if I use the splice method as given in the code above, it behaves very strangely, for example for the following arrays
[1, 2, 3], [5, 2, 1, 4], the result should be: [3, 5, 4]
when I use this line
final.splice(final.indexOf(current_array[j], 1));
instead of
delete final[final.indexOf(current_array[j])];
and return the final array it returns this [ 4 ]
here is the array values at each iteration
round (0, 0): 1
round (0, 1): 1,2
round (0, 2): 1,2,3
round (1, 0): 1,2,3,5
round (1, 1): 1
round (1, 2):
round (1, 3): 4
once it gets to an element that exists in the array it removes all of the elements starting from this element until the end of the array.
I don't know exactly if I'm missing something, I tried to search for any similar problems but most of what I came up with was a problem of removing elements from an array that the person was looping over and hence missing with its indices .. In my case the array I'm trying to modify got nothing to do with the arrays I'm iterating through.
Also I believe splice modifies the array in place and returns the removed elements.. please correct me if I'm not getting it well.
You've misplaced a ), here's the correction:
final.splice( final.indexOf(current_array[j]), 1 );
An additional note: the algorithm adds 5 for the first array, removes it for the second, and adds it again for the third (since it isn't present in final anymore), resulting in [1,4,5].
With an odd number of arguments, the value is preserved, with an even number, it is removed.
A simpler way to get all unique values from all arrays (if that is the intent), is to count the occurrences and filter on a single occurrence:
function sym2() {
var count = {};
for ( var i in arguments ) {
console.log("Processing ", i );
for ( var k = 0; k < arguments[i].length; k ++)
count[ arguments[i][k] ] = (count[ arguments[i][k] ]||0) + 1;
}
var final = [];
for ( var i in count )
if ( count[i] == 1 )
final.push( i );
return final;
}
sym2([1, 2, 5], [2, 3, 5], [3, 4, 5]);
Note that this will return [1,4] rather than [1,4,5].
Related
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.
I am having trouble with a problem and how to address it. Mind you, I am relatively new to JavaScript and the problem feels like I am over complicating it.
The problem:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
Example
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) = false;
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) = true.
You can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
Thanks for all your comments! I wanted to update this to be a better question, and also inform you I have found a solution if someone would like to check it and see if there is a cleaner way to put it. :)
function almostIncreasingSequence(sequence) {
if(sequence.length == 2) return true;
var error = 0;
for(var i = 0; i < sequence.length - 1; i++){
if(sequence[i] >= sequence[i+1]){
var noStepBack = sequence[i-1] && sequence[i-1] >= sequence[i+1];
var noStepFoward = sequence[i+2] && sequence[i] >= sequence[i+2];
if(i > 0 && noStepBack && noStepFoward) {
error+=2;
}else{
error++;
}
}
if(error > 1){
return false;
}
}
return true;
}
Think about what your code:
sequence[i+1] - sequence[i] !== 1, variable++;
would do for the following array:[1,2,3,8,8].
From the problem description, it is not clear weather the program must remove one character. But if that is the case, the code below should do it.
function canGetStrictlyIncreasingSeq(numbers) {
var counter = 0;
var lastGreatestNumber = numbers[0];
for (var i = 1; i < numbers.length; i++) {
if (lastGreatestNumber >= numbers[i]) {
counter++;
lastGreatestNumber = numbers[i];
} else {
lastGreatestNumber = numbers[i];
}
}
if (counter <= 1)
return true;
return false;
}
var nums1 = [1, 2, 3, 4, 5]; //true
var nums2 = [1, 2, 2, 3, 4]; //true
var nums3 = [1, 3, 8, 1, 9]; //true
var nums4 = [3, 2, 5, 6, 9]; //true
var nums5 = [3, 2, 1, 0, 5]; //false
var nums6 = [1, 2, 2, 2, 3]; //false
var nums7 = [1, 1, 1, 1, 1]; //false
var nums8 = [1, 2]; //true
var nums9 = [1, 2, 2]; //true
var nums10 = [1, 1, 2, 3, 4, 5, 5]; //false
var nums11 = [10, 1, 2, 3, 4, 5]; //true
var nums12 = [1, 2, 3, 4, 99, 5, 6]; //true
console.log(canGetStrictlyIncreasingSeq(nums1));
console.log(canGetStrictlyIncreasingSeq(nums2));
console.log(canGetStrictlyIncreasingSeq(nums3));
console.log(canGetStrictlyIncreasingSeq(nums4));
console.log(canGetStrictlyIncreasingSeq(nums5));
console.log(canGetStrictlyIncreasingSeq(nums6));
console.log(canGetStrictlyIncreasingSeq(nums7));
console.log(canGetStrictlyIncreasingSeq(nums8));
console.log(canGetStrictlyIncreasingSeq(nums9));
console.log(canGetStrictlyIncreasingSeq(nums10));
console.log(canGetStrictlyIncreasingSeq(nums11));
console.log(canGetStrictlyIncreasingSeq(nums12));
Lets take a step back and think about the problem: "Given a sequence of Integers as an array" - we're dealing with arrays of data...but you already knew that.
"determine whether it is possible to obtain a strictly increasing sequence" ok, we need to make something that checks for valid sequence.
"by removing no more than one element from the array." so we can try plucking each element one-by-one and if at least one resulting array is sequential, its possible.
Now instead of one large problem we have two smaller ones
First, we're dealing with arrays, so avail yourself to JavaScript's built-in Array functions to make things easier. In the below, we use 'every()', 'forEach()', 'splice()', 'push()', and 'some()' You can read into how they work here https://www.w3schools.com/jsref/jsref_obj_array.asp It's not long and well worth your time.
Lets deal with the first problem: Determining if an array is sequential. The below function does this
function checkSequence(inputArray){
return inputArray.every(function(value, index, arr){
if (index == 0 && value < arr[index + 1]) {return true}
else if (index < arr.length && value < arr[index + 1] && value > arr[index - 1]) {return true}
else if (index = arr.length - 1 && value > arr[index - 1]) {return true}
else {return false}
});
}
It takes an input array, and uses an Array built-in function called every(), which runs a test on each element in an array
and returns 'true' if all the elements test true. Our test expects the first element to always be lower less than the second
for any given element to be greater than the previous, and less than the next, and for the last element to be greater than the next-to-last
if any element does not satisfy this test, the whole thing returns false
Now we have a means of seeing of an array is sequential, which will make the next part much easier
Now we make another function to pluck out individual elements and see if anythign works
function isPossible(input){
var results = []; //we will store our future results here
input.forEach(function(value, index, arr){
copy = Array.from(arr); //we work on a copy of 'arr' to avoid messing it up (splice mangles what you give it, and we need the un-maimed version for later iterations)
copy.splice(index, 1); //remove an element from copy (a copy of 'arr')
results.push(checkSequence(copy)); //see if it is still in sequence
});
return results.some(function(value){return value});
}
We first make an array to store the results of each attempt into the array 'results' we will use it later.
Then, we take a supplied array 'input' and use "forEach()", which performs a function with each element in an array.
for each element, we make a new array with that element removed from it, and we run the "checkSequence()"
function we made before on it, and finally store the result in the results array.
When the forEach is done, we take the results array and use 'some()' on it, which works just like 'every()'
only it returns true if at least one value is true
Now, you simply call isPossible(your_array) and it will satisfy the problem
Taking into account Patrick Barr's suggestion and assuming that es6 and arrow functions are fine, this solution using Array.prototype.filter could work. The filter itself will return array of elements that should be removed to satisfy conditions of the problem:
UPDATED
function isSequential(array) {
return array && array.length > 0 ? array.filter((x,i) => x >= array[i + 1] || array[i + 1] <= array[i - 1]).length < 2 : false;
}
console.log(isSequential([1]));
console.log(isSequential([1,2,4,5,6]));
console.log(isSequential([1,2,2,3,4,5,6]));
console.log(isSequential([1,4,3,2,5,6]));
console.log(isSequential([1,2,3,4,5,6]));
console.log(isSequential([1,2,0,3,4]));
console.log(isSequential([1,1]));
console.log(isSequential([1,2,0,1,2]));
console.log(isSequential([1,2,3,1,2,3]));
console.log(isSequential([]));
console.log(isSequential([1,0,0,1]));
console.log(isSequential([1,2,6,3,4])); //should be true, but return false
Hi I'm struggling to solve this problem. How to create a javascript function that takes any number of arrays as arguments, then returns an array of elements that only appear in one of the arrays. All items that appear in multiple arrays are removed. Getting nowhere with a solution, suspect I'm not approaching it in the right way, stumped!
Edit: the other question addresses eliminating duplicate values in one array, I need to compare x number of separate arrays and return the values that aren't duplicated between arrays. So ([5,6,7],[5,8,9]) returns [6,7,8,9].
function sym(args) {
var ans = [];
for(var i =0;i<arguments.length;i++){
var tempArr = arguments[i].filter(function(el){
var filtTrue = false;
for(var j = 0;j<arguments.length;j++){
if(Array.isArray(arguments[j]) && arguments[j] !== arguments[i]){
if(arguments[j].indexOf(el) === -1){
filtTrue = true;
}}
}
return filtTrue;
});
ans = ans.concat(tempArr);
}
return ans;
}
Here's one way to do it. The idea here is that you create a map for keeping counts of all the items in the array. You then cycle through each array, look up each value in the map and, if found, you increment its count. If not found, you set the count to 1. Then, when done with all the arrays, you collect any items that have a count of 1.
You weren't specific about what to do if an item appears more than once in the same array, but not in any other array. This first solution will not include that item (since it detects duplicates). It could be adapted (with a little more complexity) to allow that item if that was an issue (see 2nd code block below for that implementation).
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {};
//count all items in the array
for (var i = 0; i < arguments.length; i++){
arguments[i].forEach(function(item) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
});
}
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
If you want to include items that are present more than once in a single array, but not present in any other array, then you can use this slightly more complicated adaptation:
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {}, currentMap;
//count all items in the array
for (var i = 0; i < arguments.length; i++){
currentMap = {};
arguments[i].forEach(function(item) {
// if we haven't already counted this item in this array
if (!currentMap.hasOwnProperty(item)) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
}
// keep track of whethere we've already counted this item in this array
currentMap[item] = true;
});
}
// output all items that have a cnt of 1
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
Working demo: http://jsfiddle.net/jfriend00/bete5k3n/
I know this is increadibly late but this is another way to do it. Maybe not the most rigorous one but certainly creative. The method Array.symmetricDifference() expects any number of arguments and returns the symmetric difference of those arguments.
Array.prototype.symmetricDifference = function() {
var args = [];
// copy arguments into a real array and get rid of duplicates with filter
for(var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
args[i] = args[i].filter(function(item, pos, self) {
return self.indexOf(item) == pos;
});
}
var diff = args[0];
// iterate through every arguments in args.
// concatenate the first two arguments to form a new set.
// now every number in this new set that was contained in both arguments
// from before will be contained at least twice in this new set.
for(var j = 1; j < args.length; j++) {
//sort the new set so that duplicates are next to each other.
diff = diff.concat(args[j]).sort();
var index = 0;
// now iterate through the new set and delete both duplicates if you
// find any. Otherwise proceed to the next index.
while(index < diff.length) {
// if duplicate is found delete both, otherwise look at next index.
diff[index] === diff[index + 1] ? diff.splice(index, 2) : index++;
}
}
return diff;
};
You can invoke that method on any array or create a new one and invoke it on that one like this for example:
// take any number of arrays
var a = [3, 3, 3, 2, 5];
var b = [2, 1, 5, 7];
var c = [3, 4, 6, 6];
var d = [1, 2, 3];
var e = [5, 3, 9, 8];
var f = [1];
// invoke the method on "solution" with any number of arguments
// and store it in solution.
var solution = solution.symmetricDifference(a,b,c,d,e,f);
console.log(solution); // [1, 2, 4, 5, 6, 7, 8, 9]
I hope this helps!
Finding unique items in multiple arrays
function uniqueItemsInArrays(...args){
let allItems = [];
allItems = allItems.concat(...args)
return allItems.filter(function(item, pos, self) {
return self.indexOf(item) === pos && self.indexOf(item,pos+1) === -1;
});
}
uniqueItemsInArrays( [1, 5, 1, 8, 1, 2],
[2, 2, 9, 3, 5],
[1, 4, 7, 6] );
The above code uses ES6 rest parameters to access all the arrays passed as arguments. Then using the concat() function, I am joining all the individual arrays to a single array. Finally, filter function has been used to identify and return the unique items from this array. The logic here is to find out the first index of the current item and if there are no more occurrence from the first index then we return that item.
I have two arrays where I need to compare values and get the duplicates. I wrote most of the code but seem to be stumped on the comparison.
Here is my code:
function compare(arr1, arr2) {
for (var i = 0; i< arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
console.log[i];
}
}
}
}
compare([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
I get the for loops to print all of the numbers, but for some reason the if statement comparison doesn't work. Is there something I am not getting about comparing values in arrays?
I am not looking for a straight up answer but guidance if possible.
Your code is quadratic in time since it iterates the second array for each item in the first array. A linear time solution is to convert the first array into a hash table, and then, for each item in the second one, instantly check if it is in the hash.
function intersect(a, b) {
var hash = {};
a.forEach(function(x) { hash[x] = 1 });
return b.filter(function(x) { return hash[x] === 1 });
}
c = intersect([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
document.write(c)
Do note, however, that this only works if items to compare are primitives, you cannot put objects in a hash, so the code has to be quadratic:
function intersect(a, b) {
return a.filter(function(x) {
return b.indexOf(x) >= 0
});
}
a = {x:'a'};
b = {x:'b'};
c = {x:'c'};
d = {x:'d'};
i = intersect([a,b,c], [a,b,d]);
document.write(JSON.stringify(i));
Regarding your bit about improving your current code, I suggest that you make your javascript more idiomatic, in particular,
get used to iteration methods instead of for loops
check the repertoire of built-in functions and use them wherever possible
and, for sanity's sake, never ever use ==
What would be the best way to shuffle an array of numbers with the condition that each number must be +3 or -3 of the next/prev number? So, for example [0,1] wouldn't work, but [0,3] would.
Thanks!
Looking at the screenshot it seems you're wanting to pick a random assortment from the list, with no 2 choices being within 3 of each other.
This code takes an array, and gives you a subset of the array satisfying that condition.
You can specify a maximum number of selections too, although you might not always get that many.
var src = [0,1,2,3,4,5,6,7,8,9,10,11,12];
var getRnd = function(max){
var output = [];
var newSrc = src.slice();
var test, index, i, safe;
while (newSrc.length > 0 && output.length < max){
index = Math.floor(Math.random()*newSrc.length);
test = newSrc.splice(index,1);
//Make sure it's not within 3
safe = true;
for (i=0; i<output.length;i++){
if(Math.abs(test-output[i]) < 3){
//abort!
safe=false;
}
}
if(safe){
output.push(test);
}
}
return output;
};
alert(getRnd(4));
A way (likley not the fastes) would be to:
sort array
pick random element to start new shuffled array with (mark element in sorted array as used or remove)
with binary search find next element that is +3 or -3 for the last one (randomly pick between -3 and +3). Make sure element is not marked as used before (otherwise find another one)
repeat 3 till you can find elements.
you either picked all elements from sorted array or such shuffling is not possible.
I think you get O(N*logN) with this (sorting N*logN and picking N elements with logN for each serch).
Assuming that the values in the array cannot be duplicated.
function one(array, mod){
var modArray = [];
for(var index in array){
var item = array[index];
var itemMod = item%3;
if(itemMod === mod){
modArray.push(item);
}
}
return modArray();
}
function two(modArray){
var sortedArray = // sort highest to lowest
for(var index in sortedArray ){
var item = array[index];
if(index > 0 && item[index-1] === item[index]-3){
}else{return false;}
}
return sortedArray.length;
}
function main(array){
var a1 = one(array, 0);
var a2 = one(array, 1);
var a3 = one(array, 2);
var a1c = two(a1);
var a2c = two(a2);
var a3c = two(a3);
return // if a1c is greatest then a1, if a2c greatest then a2 ... etc
}
I think you must be using the phrase "shuffle" in some non-standard way. If all of the numbers are already within +-3 of each other, then sorting the array will put them in the right order, unless there are duplicates, I guess.
More examples would probably be helpful. For instance, are these examples valid, and the sort of thing you're looking for?
[0, 3, 3] -> [3, 0, 3]
[9, 3, 6, 0, 6] -> [0, 3, 6, 9, 6]
[3, 3, 6, 0, 6] -> [0, 3, 6, 3, 6]
It feels like this is probably a solved problem in graph theory - some kind of network traversal with a maximum/minimum cost function.