Reputation: 862
The task was to take an array and return the earliest duplicate, and if there are none return -1. I wrote it like this:
function firstDuplicate(a) {
let singles = [];
for (let i = 0; i < a.length; i++) {
if (singles.indexOf(a[i]) == -1) {
singles.push(a[i]);
}
else {
return a[i];
}
}
return -1;
}
It passed all tests except the hidden speed test. Is there another way to write this faster in JS? I saw a Java solution that used sets instead of arrays but I wanted to stick with JS.
Upvotes: 3
Views: 326
Reputation: 51886
You can use Set
in JavaScript to achieve this as well:
function firstDuplicate(array) {
const set = new Set()
for (const value of array) {
if (set.has(value)) {
return value
}
set.add(value)
}
return -1
}
console.log(firstDuplicate(['a', 1, 'b', 2, 'c', 1, 2, 3]))
The problem with your solution, as explained by @Zabuza, is your use of indexOf()
which changes the time complexity of your algorithm from O(n) to O(n2), because each indexOf()
is O(n).
Using Set
instead Array
takes advantage of hashing, which changes your lookup time by using has()
for duplicates from O(n) to O(1), thus bringing the algorithm back to O(n) complexity overall.
Upvotes: 4
Reputation: 5041
Try this one. It should give you some more speed in the cases where there are no duplicates in a large array.
function firstDuplicate(a) {
let singles = new Set(a);
if(singles.size == a.length)
return -1;
let temp = [];
for (let i = 0; i < a.length; i++) {
if (temp.indexOf(a[i]) == -1) {
temp.push(a[i]);
}
else {
return a[i];
}
}
}
Upvotes: 0
Reputation: 2263
Instead of pushing on singles just allocate a frequency array and increase the frequency when looping through the original array. The first time the frequency is 2 you have the earliest duplicate.
Increasing by '1' the frequency at the ith element of the array is for sure faster then push on an array and then any time searching on it.
Upvotes: 0