Difficulty: Medium, Asked-in: Google
Key takeaway: An excellent problem to learn time complexity optimization using mathematical approach. Sometimes mathematical insights into the problem can help us to get efficient solutions.
In array of size 2N (N > 1), there are N + 1 unique elements and exactly one of these elements is repeated N times. Write a program to find the element repeated N times.
Input: X[] = [1, 2, 2, 3], Output: 2
Input: X[] = [2, 1, 2, 5, 3, 2, 2, 4], Output: 2
Input: X[] = [5, 1, 5, 2, 5, 3, 5, 4, 6, 5], Output: 5
A simple approach would be to traverse the array and count frequency of each element using hash table. During the traversal, if we find an element with frequency count greater than 1, we return that element. Why are we returning element with frequency count greater than 1? The idea is simple: There is only one element repeated N times and other N elements are unique.
From another perspective, we only need to find the repeated element in the array. So we take a hash table of size equal to the total number of unique elements i.e. N + 1 and run a while loop till i < n (Here n = 2N) to update the count of each element. When we find an element with a count greater than 1, we return that element as an output.
int nRepeatedElement(int X[], int n)
{
unordered_map<int, int> H;
int i = 0;
while (i < n)
{
H[X[i]] = H[X[i]] + 1;
if(H[X[i]] > 1)
return X[i];
i = i + 1;
}
}
At each iteration, we are doing constant operations because insertion and searching in the hash table will take O(1) time average. In the best case, repeated element will be present at indexes 0 and 1 and above code will perform constant operations. So time complexity in the best case = O(1). What would be the worst-case scenario?
In the worst case, the first N elements are unique and the remaining N repeated elements are present at the last N positions. So the above while loop will run N times in the worst case to find the repeated element. Time complexity in the worst case = O(N)
We are using O(N) extra space to store frequency of elements in the hash table. Space complexity = O(N).
Can we think to solve this problem in O(N) time without using extra space? As given in the problem, if an element x is repeated, then it must be the element that has been repeated N times because all other elements are unique. How can we use this insight to solve this problem efficiently in O(1)? Let's think!
Suppose indexes of all x’s in the array are X1, X2, ... XN, where X1 < X2 <...< XN. Let's calculate the average gap between all consecutive x’s.
As array size is 2N, so max possible value of XN = 2N - 1, min possible value of X1 = 0. If we put the values of XN and X1 in the above formula, we will get the max upper limit of the average gap.
If the average gap is 3, it means: Gap between some x’s is more than 3 and the gap between some x’s is less than 3. So we can argue that: There must exist at least two x’s in the array such that their gap is at most 3. In simple words: If half array elements are repeated, it doesn’t matter how we shuffle it; for one of the repeated elements, there has to be another repeated element at least three positions away. Otherwise, array size will not be 2N. Think!
If we just check elements at gaps 1, 2 and 3, then we definitely find the repeated elements.
int nRepeatedElement(int X[], int n)
{
for (int k = 1; k <= 3; k = k + 1)
{
for (int i = 0; i < n - k; i = i + 1)
{
if (X[i] == X[i + k])
return X[i];
}
}
}
We are using two nested loops and doing one comparison operation at each iteration of the inner loop. In the worst case, outer loop will run three times, and we need to traverse each element via inner loop. So time complexity = Time complexity of outer loop * Time complexity of inner loop = O(1)*O(n) = O(n) = O(N).
We are using constant extra space. So space complexity = O(1)
int nRepeated(int X[], int n)
{
for (int i = 3; i < n; i = i + 1)
{
if (X[i] == X[i - 1] || X[i] == X[i - 2] || X[i] == X[i - 3])
return X[i]
}
}
Please write comments if you find an error or you want to share more insights about the topic. Enjoy learning, Enjoy coding, Enjoy algorithms!