Skip to content
Related Articles

Related Articles

Find duplicates in O(n) time and O(1) extra space | Set 1

View Discussion
Improve Article
Save Article
  • Difficulty Level : Medium
  • Last Updated : 06 Jul, 2022
View Discussion
Improve Article
Save Article

Given an array of n elements that contains elements from 0 to n-1, with any of these numbers appearing any number of times. Find these repeating numbers in O(n) and using only constant memory space.

Example: 

Input : n = 7 and array[] = {1, 2, 3, 6, 3, 6, 1}
Output: 1, 3, 6

Explanation: The numbers 1 , 3 and 6 appears more
than once in the array.

Input : n = 5 and array[] = {1, 2, 3, 4 ,3}
Output: 3

Explanation: The number 3 appears more than once
in the array.

This problem is an extended version of the following problem. 
Find the two repeating elements in a given array 
Method 1 and Method 2 of the above link are not applicable as the question says O(n) time complexity and O(1) constant space. Also, Method 3 and Method 4 cannot be applied here because there can be more than 2 repeating elements in this problem. Method 5 can be extended to work for this problem. Below is the solution that is similar to Method 5.

Complete Interview Preparation - GFG

Efficient approach:

  • Approach: The elements in the array is from 0 to n-1 and all of them are positive. So to find out the duplicate elements, a HashMap is required, but the question is to solve the problem in constant space. There is a catch, the array is of length n and the elements are from 0 to n-1 (n elements). The array can be used as a HashMap. 
    Problem in the below approach. This approach only works for arrays having at most 2 duplicate elements i.e It will not work if the array contains more than 2 duplicates of an element. For example: {1, 6, 3, 1, 3, 6, 6} it will give output as : 1 3 6 6.
  • Note: The above program doesn’t handle 0 cases (If 0 is present in array). The program can be easily modified to handle that also. It is not handled to keep the code simple. (Program can be modified to handle 0 cases by adding plus One(+1) to all the values. also subtracting One from the answer and by writing { arr [abs(arr[i]) – 1] } in code)

In other approach below, the discussed solution prints repeating elements only once.

  • Approach: The basic idea is to use a HashMap to solve the problem. But there is a catch, the numbers in the array are from 0 to n-1, and the input array has length n. So, the input array can be used as a HashMap. While Traversing the array, if an element ‘a’ is encountered then increase the value of a%n‘th element by n. The frequency can be retrieved by dividing the a % n’th element by n.
  • Algorithm: 
    1. Traverse the given array from start to end.
    2. For every element in the array increment the arr[i]%n‘th element by n.
    3. Now traverse the array again and print all those indexes i for which arr[i]/n is greater than 1. Which guarantees that the number n has been added to that index
    4. This approach works because all elements are in the range from 0 to n-1 and arr[i] would be greater than n only if a value “i” has appeared more than once.

Below is the implementation of the above approach:

C++




// C++ code to find
// duplicates in O(n) time
#include <bits/stdc++.h>
using namespace std;
  
int main()
{
    int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
    int arr_size = sizeof(numRay) / sizeof(numRay[0]);
    // count the frequency
    for (int i = 0; i < arr_size; i++) {
        numRay[numRay[i] % arr_size]
            = numRay[numRay[i] % arr_size] + arr_size;
    }
    cout << "The repeating elements are : " << endl;
    for (int i = 0; i < arr_size; i++) {
        if (numRay[i] >= arr_size * 2) {
            cout << i << " " << endl;
        }
    }
    return 0;
}
  
// This code is contributed by aditya kumar (adityakumar129)


C




// C++ code to find
// duplicates in O(n) time
  
#include <stdio.h>
  
int main()
{
  
    int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
    int arr_size = sizeof(numRay) / sizeof(numRay[0]);
    
    
    // count the frequency
    for (int i = 0; i < arr_size; i++) {
        numRay[numRay[i] % arr_size]
            = numRay[numRay[i] % arr_size] + arr_size;
    }
    printf("The repeating elements are : \n");
    for (int i = 0; i < arr_size; i++) {
        if (numRay[i] >= arr_size * 2) {
            printf("%d  \n", i );
        }
    }
    return 0;
}
// This code is contributed by aditya kumar (adityakumar129)


Java




// JAVA code to find
// duplicates in O(n) time
  
class Leet442 {
  
    public static void main(String args[])
    {
        int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
  
        for (int i = 0; i < numRay.length; i++) {
            numRay[numRay[i] % numRay.length]
                = numRay[numRay[i] % numRay.length]
                  + numRay.length;
        }
        System.out.println("The repeating elements are : ");
        for (int i = 0; i < numRay.length; i++) {
            if (numRay[i] >= numRay.length * 2) {
                System.out.println(i + " ");
            }
        }
    }
}


Python




# Python3 code to find duplicates in O(n) time
numRay = [0, 4, 3, 2, 7, 8, 2, 3, 1]
arr_size = len(numRay)
for i in range(arr_size):
  
    x = numRay[i] % arr_size
    numRay[x] = numRay[x] + arr_size
  
print("The repeating elements are : ")
for i in range(arr_size):
    if (numRay[i] >= arr_size*2):
        print(i, " ")
  
# This code is contributed by 29AjayKumar


C#




// C# code to find
// duplicates in O(n) time
using System;
class Leet442 
{
    public static void Main(String []args)
    {
        int []numRay = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
  
        for (int i = 0; i < numRay.Length; i++) 
        {
            numRay[numRay[i] % numRay.Length]
                = numRay[numRay[i] % numRay.Length]
                + numRay.Length;
        }
        Console.WriteLine("The repeating elements are : ");
        for (int i = 0; i < numRay.Length; i++) 
        {
            if (numRay[i] >= numRay.Length * 2) 
            {
                Console.WriteLine(i + " ");
            }
        }
    }
}
  
// This code is contributed by shivanisinghss2110


Javascript




<script>
    // Javascript code to find
    // duplicates in O(n) time
    let numRay = [ 0, 4, 3, 2, 7, 8, 2, 3, 1 ];
    let arr_size = numRay.length;
     
     
    // count the frequency
    for (let i = 0; i < arr_size; i++) {
        numRay[numRay[i] % arr_size]
            = numRay[numRay[i] % arr_size] + arr_size;
    }
    document.write("The repeating elements are : " + "</br>");
    for (let i = 0; i < arr_size; i++) {
        if (numRay[i] >= arr_size * 2) {
            document.write(i + " " + "</br>");
        }
    }
  
// This code is contributed by mukesh07.
</script>


Output

The repeating elements are : 
2 
3 

Complexity Analysis: 

  • Time Complexity: O(n), Only two traversals are needed. So the time complexity is O(n).
  • Auxiliary Space: O(1), No extra space is needed, so the space complexity is constant.

Another efficient approach: Modifying array by making visited elements -ve (visited once) or greater than n (visited twice or more)

  • Approach:
    Increment the array elements by 1 (arr[i]+1) to handle occurrence of 0. Traverse the array and for every element that has been visited the first time, make the element at index equal to the value of the current element as negative. If element has already been visited before, add it (arr[i]-1) to result vector and make the element at index equal to the value of current element more than n (by multiplying it with (n+1)) to avoid adding it to result vector, incase it occurs again. 
  • Algorithm:
    • Traverse the array and increment each element  by 1. This is done to remove occurrence of 0 from the array. Later, while adding the duplicate elements in the result vector, we decrement elements by 1 to get actual value.
    • Declare result vector.
    • Declare a count variable to count the occurrence of (n-1)th element in the array. 
      For eg : array = [0,2,4,3,4], n=5, then we need the count variable to count the occurrence of 4. 
      In the algorithm, we need to access elements present at index equal to other element values, meaning we have to access values like array[array[i]]. For eg: if i=0, we access array[array[i]] = array[array[0]] = array[1] = 2. Similarly, we might need to access the element at index equal to largest value possible in the array, i.e., n-1 (array[array[n-1]]). However, we incremented each element by 1 and thus largest possible element in the array became n. In 0-based indexing array[n] returns garbage value  and thus our algorithm cannot calculate the occurrence of the largest possible element in the array. Hence we need the count variable to count its occurrence separately and later add it to result vector if found duplicate.
    • Run a for loop from 0 to n and in each iteration of the loop:
      • Calculate index value – 
        Since we need to access elements present at index equal to other element values, index is the absolute value of arr[i]. If abs(arr[i]) is greater than n, then index is equal to abs(arr[i])/(n+1) else abs(arr[i]). 
        If an element ‘x’ occurs twice in the array, we negate the element present at x, i.e., array[x] = -array[x], but if it occurs more than twice, then, to avoid it from getting pushed to result vector again, we make element at x equal to a number greater than n (a number that would never occur in the array). To do this, we multiply it by (n+1), i.e., array[x] = array[x]*(n+1). We cannot multiply with n as if array[x] = 1, then array[x]*n = n, which is the largest possible element and can occur in the array. 
        Thus, during traversal, if we come across array[x] which is greater than n, we need to calculate array[x]/(n+1) to get the original value of index.
         
      • Check if obtained index value is equal to n, if so, increment the count variable and move to the next iteration, as we will calculate the occurrence of n separately.
         
      • Get the value of element at calculated index in a variable and run the following else-if conditions:
        • If this value is less than 0 (-ve), it means that element equal to its index has appeared twice, thus push the value of index-1 (as element values had been incremented earlier) in result vector. Going forward, as this index value has already been pushed to result vector, we don’t want a duplicate in result vector if it occurs again and thus, make the value of the element present at this index greater than n by multiplying it with (n+1).
        • If this value is greater than n, it means that element equal to the index value has already been pushed to result vector and nothing needs to be done. So just continue to the next iteration.
        • If this value is between 0 and n, it means that the element equal to the index value has appeared for the first time and thus make it negative.
           
    • After exiting from the for loop, if the value of count variable is more than 1, it means that the largest possible element (n) has duplicates in the array and thus, push (n-1) to result vector.
    • Check if size of result vector is 0, if so, push -1 as there are no duplicates. Otherwise, sort the result vector
    • Return the result vector.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
  
vector<int> duplicates(int arr[], int n)
{
  
    // Increment array elements by 1
    for (int i = 0; i < n; i++) {
        arr[i] += 1;
    }
  
    // result vector
    vector<int> res;
  
    // count variable for count of
    // largest element
    int count = 0;
  
    for (int i = 0; i < n; i++) {
  
        // Calculate index value
        int index = abs(arr[i]) > n ? abs(arr[i]) / (n + 1)
                                    : abs(arr[i]);
  
        // Check if index equals largest element value
        if (index == n) {
            count++;
            continue;
        }
  
        // Get element value at index
        int val = arr[index];
  
        // Check if element value is negative, positive
        // or greater than n
        if (val < 0) {
            res.push_back(index - 1);
            arr[index] = abs(arr[index]) * (n + 1);
        }
        else if (val > n)
            continue;
        else
            arr[index] = -arr[index];
    }
  
    // If largest element occurs more than once
    if (count > 1)
        res.push_back(n - 1);
  
    if (res.size() == 0)
        res.push_back(-1);
    else
        sort(res.begin(), res.end());
  
    return res;
}
  
// Driver Code
int main()
{
    int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
    int n = sizeof(numRay) / sizeof(numRay[0]);
  
    vector<int> ans = duplicates(numRay, n);
    for (int i : ans)
        cout << i << ' ' << endl;
    return 0;
}


Output

2 
3 

Complexity Analysis:

  • Time Complexity: O(n), Only two traversals are needed. So the time complexity is O(n).
  • Auxiliary Space: O(1). 

My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!