Remove duplicates from Array without using Hash Table - arrays

i have an array which might contain duplicate elements(more than two duplicates of an element). I wonder if it's possible to find and remove the duplicates in the array:
without using Hash Table (strict requirement)
without using a temporary secondary array. No restrictions on complexity.
P.S: This is not Home work question
Was asked to my friend in yahoo technical interview

Sort the source array. Find consecutive elements that are equal. (I.e. what std::unique does in C++ land). Total complexity is N lg N, or merely N if the input is already sorted.
To remove duplicates, you can copy elements from later in the array over elements earlier in the array also in linear time. Simply keep a pointer to the new logical end of the container, and copy the next distinct element to that new logical end at each step. (Again, exactly like std::unique does (In fact, why not just download an implementation of std::unique and do exactly what it does? :P))

O(NlogN) : Sort and replace consecutive same element with one copy.
O(N2) : Run nested loop to compare each element with the remaining elements in the array, if duplicate found, swap the duplicate with the element at the end of the array and decrease the array size by 1.

No restrictions on complexity.
So this is a piece of cake.
// A[1], A[2], A[3], ... A[i], ... A[n]
// O(n^2)
for(i=2; i<=n; i++)
{
duplicate = false;
for(j=1; j<i; j++)
if(A[i] == A[j])
{duplicate = true; break;}
if(duplicate)
{
// "remove" A[i] by moving all elements from its left over it
for(j=i; j<n; j++)
A[j] = A[j+1];
n--;
}
}

In-place duplicate removal that preserves the existing order of the list, in quadratic time:
for (var i = 0; i < list.length; i++) {
for (var j = i + 1; j < list.length;) {
if (list[i] == list[j]) {
list.splice(j, 1);
} else {
j++;
}
}
}
The trick is to start the inner loop on i + 1 and not increment the inner counter when you remove an element.
The code is JavaScript, splice(x, 1) removes the element at x.
If order preservation isn't an issue, then you can do it quicker:
list.sort();
for (var i = 1; i < list.length;) {
if (list[i] == list[i - 1]) {
list.splice(i, 1);
} else {
i++;
}
}
Which is linear, unless you count the sort, which you should, so it's of the order of the sort -- in most cases n × log(n).

In functional languages you can combine sorting and unicification (is that a real word?) in one pass.
Let's take the standard quick sort algorithm:
- Take the first element of the input (x) and the remaining elements (xs)
- Make two new lists
- left: all elements in xs smaller than or equal to x
- right: all elements in xs larger than x
- apply quick sort on the left and right lists
- return the concatenation of the left list, x, and the right list
- P.S. quick sort on an empty list is an empty list (don't forget base case!)
If you want only unique entries, replace
left: all elements in xs smaller than or equal to x
with
left: all elements in xs smaller than x
This is a one-pass O(n log n) algorithm.
Example implementation in F#:
let rec qsort = function
| [] -> []
| x::xs -> let left,right = List.partition (fun el -> el <= x) xs
qsort left # [x] # qsort right
let rec qsortu = function
| [] -> []
| x::xs -> let left = List.filter (fun el -> el < x) xs
let right = List.filter (fun el -> el > x) xs
qsortu left # [x] # qsortu right
And a test in interactive mode:
> qsortu [42;42;42;42;42];;
val it : int list = [42]
> qsortu [5;4;4;3;3;3;2;2;2;2;1];;
val it : int list = [1; 2; 3; 4; 5]
> qsortu [3;1;4;1;5;9;2;6;5;3;5;8;9];;
val it : int list = [1; 2; 3; 4; 5; 6; 8; 9]

Since it's an interview question it is usually expected by the interviewer to be asked precisions about the problem.
With no alternative storage allowed (that is O(1) storage allowed in that you'll probably use some counters / pointers), it seems obvious that a destructive operation is expected, it might be worth pointing it out to the interviewer.
Now the real question is: do you want to preserve the relative order of the elements ? ie is this operation supposed to be stable ?
Stability hugely impact the available algorithms (and thus the complexity).
The most obvious choice is to list Sorting Algorithms, after all, once the data is sorted, it's pretty easy to get unique elements.
But if you want stability, you cannot actually sort the data (since you could not get the "right" order back) and thus I wonder if it solvable in less than O(N**2) if stability is involved.

doesn't use a hash table per se but i know behind the scenes it's an implementation of one. Nevertheless, thought I might post in case it can help. This is in JavaScript and uses an associative array to record duplicates to pass over
function removeDuplicates(arr) {
var results = [], dups = [];
for (var i = 0; i < arr.length; i++) {
// check if not a duplicate
if (dups[arr[i]] === undefined) {
// save for next check to indicate duplicate
dups[arr[i]] = 1;
// is unique. append to output array
results.push(arr[i]);
}
}
return results;
}

Let me do this in Python.
array1 = [1,2,2,3,3,3,4,5,6,4,4,5,5,5,5,10,10,8,7,7,9,10]
array1.sort()
print(array1)
current = NONE
count = 0
# overwriting the numbers at the frontal part of the array
for item in array1:
if item != current:
array1[count] = item
count +=1
current=item
print(array1)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 5, 5, 5, 6, 7, 7, 8, 9, 10, 10, 10]
print(array1[:count])#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
The most Efficient method is :
array1 = [1,2,2,3,3,3,4,5,6,4,4,5,5,5,5,10,10,8,7,7,9,10]
array1.sort()
print(array1)
print([*dict.fromkeys(array1)])#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#OR#
aa = list(dict.fromkeys(array1))
print( aa)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Related

Permuting an array with a given order without making a copy of the Array or a change to the order

I already found almost the same question asked here. But I need to do it a bit more complicated.
So here is the problem. You have an array with elements and another array with the specific order the elements of the first array should be in. Here is an example:
int[] a = {5, 35, 7, 2, 7};
int[] order = {3, 0, 2, 4, 1};
After the algorithm a should look like this:
a = {2, 5, 7, 7, 35};
The array named order must not be changed in any way and all copies of an array are forbidden. Only constant variables like a normal integer are allowed.
Note that this problem is not based on a specific language. It should be in a pseudocode-like language. Just understandable.
So does anyone here have an idea? I am sitting in front of this problem for 3 days now and hope to get some help because I think I am really stuck now.
Thank you in advance.
Given the ranges of numbers shown you could:
Add 100 times the corresponding order value to each item of a.
Sort a.
Replace every item of a by item modulo 100.
Some Python:
a = [5, 35, 7, 2, 7]
order = [3, 0, 2, 4, 1]
mult = max(a) + 1
a = [a_item + order_item * mult
for a_item, order_item in zip(a, order)]
a.sort(reverse=True)
a = [a_item % mult for a_item in a]
print(a) # [2, 5, 7, 7, 35]
I should emphasize that it works for the numbers shown; negatives and overflow considerations may limit more general applicability.
The permutation defined by order consists of one or more cycles. It is straightforward to apply one cycle to array a, but the challenge is to somehow know which array elements belong to a cycle that you already processed in that way. If there is a way to mark visited elements, like with an extra bit, then that problem is solved. But using an extra bit is a cover-up for an array with additional data. So that must be ruled out.
When no possibilities exist to perform such marking, then there still is a way out: only perform the cycle operation on array a when you are at the left-most index of that cycle (or right most). The downside is that at every index you need to go through the cycle that index belongs to, to check whether you are indeed at its left-side extreme or not. This means that you'll cycle through the same cycle several times.
Here is how that looks in JavaScript:
function isLeftOfCycle(order, i) {
let j = order[i];
while (j > i) {
j = order[j];
}
return (j === i); // a boolean
}
function applyCycle(arr, order, i) {
let temp = arr[i];
let k = i;
let j = order[i];
while (j > i) {
arr[k] = arr[j];
k = j;
j = order[j];
}
arr[k] = temp;
}
function sort(a, order) {
for (let i = 0; i < order.length; i++) {
if (isLeftOfCycle(order, i)) {
applyCycle(a, order, i);
}
}
}
// Example run:
let a = [5, 35, 7, 2, 7];
let order = [3, 0, 2, 4, 1];
sort(a, order);
console.log(a);
Obviously, this comes at a price: the time complexity is no longer O(n), but O(n²).

Finding for each array element, the left smaller elements. O(n)

There is a famous problem which I've been looking for, which is:
On a given array, we are trying to build another array at the same size,
which each element in the new array will be the number of the smaller elements from its left in the original array (in a row). I've been searching here in StackOverflow, and I've only found solutions in O(nlogn). I think I've found a solution at O(n).
int[] arr = {8, 4, 3, 2, 10, 9, 7, 6, 12};
Stack<Integer> stack = new Stack<>();
int[] newArr = new int[arr.length];
// Each sequence is at least 1;
for (int i = 0; i < newArr.length; i++) {
newArr[i] = 1;
}
// For each element, if it is smaller than
// the previous one, push it into the stack.
// Otherwise, compare it to all the elements
// in the stack which are smaller or equals to it,
// and summarize their values in the newArr.
stack.push(arr[0]);
for (int i = 1; i < arr.length; i++) {
if (arr[i] >= arr[i-1]) {
int j = i - 1;
while (!stack.isEmpty() && stack.top() <= arr[i]) {
arr[i] += newArr[j];
stack.pop();
j--;
}
}
stack.push(arr[i);
}
Now, the complexity time, is O(n), because any value is compared only once,
and in the worst case, where there are 'n' numbers, and they are divided into
'k' descending groups (Ex. {18, 12, 11, 9, 17, 8, 6, 4, 15, 3, 2, 1}), we're
activating the second loop only 'k' times, for 'n/k' elements. That's why
the 'k' variable does not matters and we are left with O(n) in the worst case.
* I forgot to mention, that the newArr in the code should look like this:
{1, 1, 1, 1, 5, 1, 1, 1, 9} *
Let me know if I'm right, it's really important for me.
Sincerely,
Uriah.
Yes, absolutely right with your argument. The time complexity of your code is O(n).
It can also be easily proven by the fact that each number is added and popped from the stack exactly once. Thus making it O(n).
Alternate algorithm to do the same task (lot more intuitive):
// push index instead of number itself
stack.push(0);
for (int i = 1; i < arr.length; i++) {
while (!stack.isEmpty() && arr[stack.top()] <= arr[i])
stack.pop();
if(stack.isEmpty())
new_arr[i]=i+1;
else
new_arr[i]=i-stack.top()
stack.push(i);
}
As you can notice, I push the index instead of number. That makes calculation of new array intuitive (just calculate difference between two indexes).

Is it possible to invert an array with constant extra space?

Let's say I have an array A with n unique elements on the range [0, n). In other words, I have a permutation of the integers [0, n).
Is possible to transform A into B using O(1) extra space (AKA in-place) such that B[A[i]] = i?
For example:
A B
[3, 1, 0, 2, 4] -> [2, 1, 3, 0, 4]
Yes, it is possible, with O(n^2) time algorithm:
Take element at index 0, then write 0 to the cell indexed by that element. Then use just overwritten element to get next index and write previous index there. Continue until you go back to index 0. This is cycle leader algorithm.
Then do the same starting from index 1, 2, ... But before doing any changes perform cycle leader algorithm without any modifications starting from this index. If this cycle contains any index below the starting index, just skip it.
Or this O(n^3) time algorithm:
Take element at index 0, then write 0 to the cell indexed by that element. Then use just overwritten element to get next index and write previous index there. Continue until you go back to index 0.
Then do the same starting from index 1, 2, ... But before doing any changes perform cycle leader algorithm without any modifications starting from all preceding indexes. If current index is present in any preceding cycle, just skip it.
I have written (slightly optimized) implementation of O(n^2) algorithm in C++11 to determine how many additional accesses are needed for each element on average if random permutation is inverted. Here are the results:
size accesses
2^10 2.76172
2^12 4.77271
2^14 6.36212
2^16 7.10641
2^18 9.05811
2^20 10.3053
2^22 11.6851
2^24 12.6975
2^26 14.6125
2^28 16.0617
While size grows exponentially, number of element accesses grows almost linearly, so expected time complexity for random permutations is something like O(n log n).
Inverting an array A requires us to find a permutation B which fulfills the requirement A[B[i]] == i for all i.
To build the inverse in-place, we have to swap elements and indices by setting A[A[i]] = i for each element A[i]. Obviously, if we would simply iterate through A and perform aforementioned replacement, we might override upcoming elements in A and our computation would fail.
Therefore, we have to swap elements and indices along cycles of A by following c = A[c] until we reach our cycle's starting index c = i.
Every element of A belongs to one such cycle. Since we have no space to store whether or not an element A[i] has already been processed and needs to be skipped, we have to follow its cycle: If we reach an index c < i we would know that this element is part of a previously processed cycle.
This algorithm has a worst-case run-time complexity of O(n²), an average run-time complexity of O(n log n) and a best-case run-time complexity of O(n).
function invert(array) {
main:
for (var i = 0, length = array.length; i < length; ++i) {
// check if this cycle has already been traversed before:
for (var c = array[i]; c != i; c = array[c]) {
if (c <= i) continue main;
}
// Replacing each cycle element with its predecessors index:
var c_index = i,
c = array[i];
do {
var tmp = array[c];
array[c] = c_index; // replace
c_index = c; // move forward
c = tmp;
} while (i != c_index)
}
return array;
}
console.log(invert([3, 1, 0, 2, 4])); // [2, 1, 3, 0, 4]
Example for A = [1, 2, 3, 0] :
The first element 1 at index 0 belongs to the cycle of elements 1 - 2 - 3 - 0. Once we shift indices 0, 1, 2 and 3 along this cycle, we have completed the first step.
The next element 0 at index 1 belongs to the same cycle and our check tells us so in only one step (since it is a backwards step).
The same holds for the remaining elements 1 and 2.
In total, we perform 4 + 1 + 1 + 1 'operations'. This is the best-case scenario.
Implementation of this explanation in Python:
def inverse_permutation_zero_based(A):
"""
Swap elements and indices along cycles of A by following `c = A[c]` until we reach
our cycle's starting index `c = i`.
Every element of A belongs to one such cycle. Since we have no space to store
whether or not an element A[i] has already been processed and needs to be skipped,
we have to follow its cycle: If we reach an index c < i we would know that this
element is part of a previously processed cycle.
Time Complexity: O(n*n), Space Complexity: O(1)
"""
def cycle(i, A):
"""
Replacing each cycle element with its predecessors index
"""
c_index = i
c = A[i]
while True:
temp = A[c]
A[c] = c_index # replace
c_index = c # move forward
c = temp
if i == c_index:
break
for i in range(len(A)):
# check if this cycle has already been traversed before
j = A[i]
while j != i:
if j <= i:
break
j = A[j]
else:
cycle(i, A)
return A
>>> inverse_permutation_zero_based([3, 1, 0, 2, 4])
[2, 1, 3, 0, 4]
This can be done in O(n) time complexity and O(1) space if we try to store 2 numbers at a single position.
First, let's see how we can get 2 values from a single variable. Suppose we have a variable x and we want to get two values from it, 2 and 1. So,
x = n*1 + 2 , suppose n = 5 here.
x = 5*1 + 2 = 7
Now for 2, we can take remainder of x, ie, x%5. And for 1, we can take quotient of x, ie , x/5
and if we take n = 3
x = 3*1 + 2 = 5
x%3 = 5%3 = 2
x/3 = 5/3 = 1
We know here that the array contains values in range [0, n-1], so we can take the divisor as n, size of array. So, we will use the above concept to store 2 numbers at every index, one will represent old value and other will represent the new value.
A B
0 1 2 3 4 0 1 2 3 4
[3, 1, 0, 2, 4] -> [2, 1, 3, 0, 4]
.
a[0] = 3, that means, a[3] = 0 in our answer.
a[a[0]] = 2 //old
a[a[0]] = 0 //new
a[a[0]] = n* new + old = 5*0 + 2 = 2
a[a[i]] = n*i + a[a[i]]
And during array traversal, a[i] value can be greater than n because we are modifying it. So we will use a[i]%n to get the old value.
So the logic should be
a[a[i]%n] = n*i + a[a[i]%n]
Array -> 13 6 15 2 24
Now, to get the older values, take the remainder on dividing each value by n, and to get the new values, just divide each value by n, in this case, n=5.
Array -> 2 1 3 0 4
Following approach Optimizes the cycle walk if it is already handled. Also each element is 1 based. Need to convert accordingly while trying to access the elements in the given array.
enter code here
#include <stdio.h>
#include <iostream>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
// helper function to traverse cycles
void cycle(int i, vector<int>& A) {
int cur_index = i+1, next_index = A[i];
while (next_index > 0) {
int temp = A[next_index-1];
A[next_index-1] = -(cur_index);
cur_index = next_index;
next_index = temp;
if (i+1 == abs(cur_index)) {
break;
}
}
}
void inverse_permutation(vector<int>& A) {
for (int i = 0; i < A.size(); i++) {
cycle(i, A);
}
for (int i = 0; i < A.size(); i++) {
A[i] = abs(A[i]);
}
for (int i = 0; i < A.size(); i++) {
cout<<A[i]<<" ";
}
}
int main(){
// vector<int> perm = {4,0,3,1,2,5,6,7,8};
vector<int> perm = {5,1,4,2,3,6,7,9,8};
//vector<int> perm = { 17,2,15,19,3,7,12,4,18,20,5,14,13,6,11,10,1,9,8,16};
// vector<int> perm = {4, 1, 2, 3};
// { 6,17,9,23,2,10,20,7,11,5,14,13,4,1,25,22,8,24,21,18,19,12,15,16,3 } =
// { 14,5,25,13,10,1,8,17,3,6,9,22,12,11,23,24,2,20,21,7,19,16,4,18,15 }
// vector<int> perm = {6, 17, 9, 23, 2, 10, 20, 7, 11, 5, 14, 13, 4, 1, 25, 22, 8, 24, 21, 18, 19, 12, 15, 16, 3};
inverse_permutation(perm);
return 0;
}

Find the number of unordered pair in an array

I ran into an interesting algorithm problem:
Given an array of integer, find the number of un-ordered pairs in that array, say given {1, 3, 2}, the answer is 1 because {3, 2} is un-ordered, and for array {3, 2, 1}, the answer is 3 because {3, 2}, {3, 1}, {2, 1}.
Obviously, this can be solved by brute force with O(n^2) running time, or permute all possible pairs then eliminate those invalid pairs.
My question is does any body have any better solution and how would you do it because it seems like a dynamic programming problem. A snippet of code would be helpful
It is possible to solve this problem in O(n log n) time using a balanced binary search tree.
Here is a pseudo-code of this algorithm:
tree = an empty balanced binary search tree
answer = 0
for each element in the array:
answer += number of the elements in the tree greater then this element
add this element to the tree
If you are just looking for the number of un-ordered pair and the array is sorted in ascending order. You can use this formula n * (n - 1) / 2.
Suppose your array has n elements, for example 3 in your case. It will be 3 * 2 / 2 = 3. Assuming there are no duplicate elements.
You can use a modified version of merge sort to count the number of inversions. The trick is that while merging two sorted sub arrays you can come to know the elements which are out of place.
If there are any elements in right subarray which need to go before the ones in left subarray, they are the inverted ones.
I've written the code for this in python. You can check the explanation below it for better understanding. If you not able to understand merge sort I'd suggest you to revist merge sort after which this would be intuitive.
def merge_sort(l):
if len(l) <= 1:
return (0, l)
else:
mid = len(l) / 2
count_left, ll = merge_sort(l[0:mid])
count_right, lr = merge_sort(l[mid:])
count_merge, merged = merge(ll, lr)
total = count_left + count_right + count_merge
return total, merged
def merge(left, right):
li, ri = 0, 0
merged = []
count = 0
while li < len(left) and ri < len(right):
if left[li] < right[ri]:
merged.append(left[li])
li += 1
else:
count += 1
merged.append(right[ri])
ri += 1
if li < len(left):
merged.extend(left[li:])
elif ri < len(right):
merged.extend(right[ri:])
return count, merged
if __name__ == '__main__':
# example
l = [6, 1 , 2, 3, 4, 5]
print 'inverse pair count is %s'%merge_sort(l)[0]
Merge sort runs in n * log(n) time.
for the passed list l, merge_sort returns a tuple (in the form of (inversion_count, list)) of number of inversions and the sorted list
Merge step counts the number of inversions and stores it in the variable count.
It was in one of my practice midterms and i think a nested for loop does the job pretty nice.
public static void main(String args[])
{
int IA[] = {6,2,9,5,8,7};
int cntr = 0;
for(int i = 0; i <= IA.length-1;i++)
{
for(int j = i; j <= IA.length-1; j++)
{
if(IA[i]>IA[j])
{
System.out.print("("+IA[i]+","+ IA[j]+")"+";");
cntr++;
}
}
}
System.out.println(cntr);
}
You can use a modified merge-sort algorithm. Merging would look something like this.
merge(a, b):
i = 0
j = 0
c = new int[a.length+b.length]
inversions = 0
for(k = 0 ; k < Math.min(a.length, b.length); k++)
if(a[i] > b[j]):
inversions++
c[k] = b[j]
j++
else:
c[k] = a[i]
i++
//dump the rest of the longer array in c
return inversions
Merging is done in O(n) time. Time complexity of the whole merge sort is O(n log n)

Finding contiguous ranges in arrays

You are given an array of integers. You have to output the largest range so that all numbers in the range are present in the array. The numbers might be present in any order. For example, suppose that the array is
{2, 10, 3, 12, 5, 4, 11, 8, 7, 6, 15}
Here we find two (nontrivial) ranges for which all the integers in these ranges are present in the array, namely [2,8] and [10,12]. Out of these [2,8] is the longer one. So we need to output that.
When I was given this question, I was asked to do this in linear time and without using any sorting. I thought that there might be a hash-based solution, but I couldn't come up with anything.
Here's my attempt at a solution:
void printRange(int arr[])
{
int n=sizeof(arr)/sizeof(int);
int size=2;
int tempans[2];
int answer[2];// the range is stored in another array
for(int i =0;i<n;i++)
{
if(arr[0]<arr[1])
{
answer[0]=arr[0];
answer[1]=arr[1];
}
if(arr[1]<arr[0])
{
answer[0]=arr[1];
answer[1]=arr[0];
}
if(arr[i] < answer[1])
size += 1;
else if(arr[i]>answer[1]) {
initialize tempans to new range;
size2=2;
}
else {
initialize tempans to new range
}
}
//I have to check when the count becomes equal to the diff of the range
I am stuck at this part... I can't figure out how many tempanswer[] arrays should be used.
I think that the following solution will work in O(n) time using O(n) space.
Begin by putting all of the entries in the array into a hash table. Next, create a second hash table which stores elements that we have "visited," which is initially empty.
Now, iterate across the array of elements one at a time. For each element, check if the element is in the visited set. If so, skip it. Otherwise, count up from that element upward. At each step, check if the current number is in the main hash table. If so, continue onward and mark the current value as part of the visited set. If not, stop. Next, repeat this procedure, except counting downward. This tells us the number of contiguous elements in the range containing this particular array value. If we keep track of the largest range found this way, we will have a solution to our problem.
The runtime complexity of this algorithm is O(n). To see this, note that we can build the hash table in the first step in O(n) time. Next, when we begin scanning to array to find the largest range, each range scanned takes time proportional to the length of that range. Since the total sum of the lengths of the ranges is the number of elements in the original array, and since we never scan the same range twice (because we mark each number that we visit), this second step takes O(n) time as well, for a net runtime of O(n).
EDIT: If you're curious, I have a Java implementation of this algorithm, along with a much more detailed analysis of why it works and why it has the correct runtime. It also explores a few edge cases that aren't apparent in the initial description of the algorithm (for example, how to handle integer overflow).
Hope this helps!
The solution could use BitSet:
public static void detect(int []ns) {
BitSet bs = new BitSet();
for (int i = 0; i < ns.length; i++) {
bs.set(ns[i]);
}
int begin = 0;
int setpos = -1;
while((setpos = bs.nextSetBit(begin)) >= 0) {
begin = bs.nextClearBit(setpos);
System.out.print("[" + setpos + " , " + (begin - 1) + "]");
}
}
Sample I/O:
detect(new int[] {2,10, 3, 12, 5,4, 11, 8, 7, 6, 15} );
[2,8] [10,12] [15,15]
Here is the solution in Java:
public class Solution {
public int longestConsecutive(int[] num) {
int longest = 0;
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
for(int i = 0; i< num.length; i++){
map.put(num[i], false);
}
int l, k;
for(int i = 0;i < num.length;i++){
if(map.containsKey(num[i]-1) || map.get(num[i])) continue;
map.put(num[i], true);
l = 0; k = num[i];
while (map.containsKey(k)){
l++;
k++;
}
if(longest < l) longest = l;
}
return longest;
}
}
Other approaches here.
The above answer by template will work but you don't need a hash table. Hashing could take a long time depending on what algorithm you use. You can ask the interviewer if there's a max number the integer can be, then create an array of that size. Call it exist[] Then scan through arr and mark exist[i] = 1; Then iterate through exist[] keeping track of 4 variables, size of current largest range, and the beginning of the current largest range, size of current range, and beginning of current range. When you see exist[i] = 0, compare the current range values vs largest range values and update the largest range values if needed.
If there's no max value then you might have to go with the hashing method.
Actually considering that we're only sorting integers and therefore a comparision sort is NOT necessary, you can just sort the array using a Radix- or BucketSort and then iterate through it.
Simple and certainly not what the interviewee wanted to hear, but correct nonetheless ;)
A Haskell implementation of Grigor Gevorgyan's solution, from another who didn't get a chance to post before the question was marked as a duplicate...(simply updates the hash and the longest range so far, while traversing the list)
import qualified Data.HashTable.IO as H
import Control.Monad.Random
f list = do
h <- H.new :: IO (H.BasicHashTable Int Int)
g list (0,[]) h where
g [] best h = return best
g (x:xs) best h = do
m <- H.lookup h x
case m of
Just _ -> g xs best h
otherwise -> do
(xValue,newRange) <- test
H.insert h x xValue
g xs (maximum [best,newRange]) h
where
test = do
m1 <- H.lookup h (x-1)
m2 <- H.lookup h (x+1)
case m1 of
Just x1 -> case m2 of
Just x2 -> do H.insert h (x-1) x2
H.insert h (x+1) x1
return (x,(x2 - x1 + 1,[x1,x2]))
Nothing -> do H.insert h (x-1) x
return (x1,(x - x1 + 1,[x,x1]))
Nothing -> case m2 of
Just x2 -> do H.insert h (x+1) x
return (x2,(x2 - x + 1,[x,x2]))
Nothing -> do return (x,(1,[x]))
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (-100,100)
main = do
values <- evalRandIO (sequence (replicate (1000000) rnd))
f values >>= print
Output:
*Main> main
(10,[40,49])
(5.30 secs, 1132898932 bytes)
I read a lot of solutions on multiple platforms to this problem and one got my attention, as it solves the problem very elegantly and it is easy to follow.
The backbone of this method is to create a set/hash which takes O(n) time and from there every access to the set/hash will be O(1). As the O-Notation omit's constant terms, this Algorithm still can be described overall as O(n)
def longestConsecutive(self, nums):
nums = set(nums) # Create Hash O(1)
best = 0
for x in nums:
if x - 1 not in nums: # Optimization
y = x + 1 # Get possible next number
while y in nums: # If the next number is in set/hash
y += 1 # keep counting
best = max(best, y - x) # counting done, update best
return best
It's straight forward if you ran over it with simple numbers. The Optimization step is just a short-circuit to make sure you start counting, when that specific number is the beginning of a sequence.
All Credits to Stefan Pochmann.
Very short solution using Javascript sparse array feature:
O(n) time using O(n) additional space.
var arr = [2, 10, 3, 12, 5, 4, 11, 8, 7, 6, 15];
var a = [];
var count = 0, max_count = 0;
for (var i=0; i < arr.length; i++) a[arr[i]] = true;
for (i = 0; i < a.length; i++) {
count = (a[i]) ? count + 1 : 0;
max_count = Math.max(max_count, count);
}
console.log(max_count); // 7
A quick way to do it (PHP) :
$tab = array(14,12,1,5,7,3,4,10,11,8);
asort($tab);
$tab = array_values($tab);
$tab_contiguous = array();
$i=0;
foreach ($tab as $key => $val) {
$tab_contiguous[$i][] = $tab[$key];
if (isset($tab[$key+1])) {
if($tab[$key] + 1 != $tab[$key+1])
$i++;
}
}
echo(json_encode($tab_contiguous));

Resources