Algorithm to find two repeated numbers in an array, without sorting

前端 未结 24 2000
南方客
南方客 2020-11-28 06:58

There is an array of size n (numbers are between 0 and n - 3) and only 2 numbers are repeated. Elements are placed randomly in the array.

E.g. in {2, 3, 6, 1, 5, 4

相关标签:
24条回答
  • 2020-11-28 07:13

    OK, seems I just can't give it a rest :)

    Simplest solution

    int A[N] = {...};
    
    int signed_1(n) { return n%2<1 ? +n : -n;  } // 0,-1,+2,-3,+4,-5,+6,-7,...
    int signed_2(n) { return n%4<2 ? +n : -n;  } // 0,+1,-2,-3,+4,+5,-6,-7,...
    
    long S1 = 0;  // or int64, or long long, or some user-defined class
    long S2 = 0;  // so that it has enough bits to contain sum without overflow
    
    for (int i=0; i<N-2; ++i)
    {
       S1 += signed_1(A[i]) - signed_1(i);
       S2 += signed_2(A[i]) - signed_2(i);
    } 
    
    for (int i=N-2; i<N; ++i)
    {
       S1 += signed_1(A[i]);
       S2 += signed_2(A[i]);
    } 
    
    S1 = abs(S1);
    S2 = abs(S2);
    
    assert(S1 != S2);  // this algorithm fails in this case
    
    p = (S1+S2)/2;
    q = abs(S1-S2)/2;
    

    One sum (S1 or S2) contains p and q with the same sign, the other sum - with opposite signs, all other members are eliminated.
    S1 and S2 must have enough bits to accommodate sums, the algorithm does not stand for overflow because of abs().

    if abs(S1)==abs(S2) then the algorithm fails, though this value will still be the difference between p and q (i.e. abs(p - q) == abs(S1)).

    Previous solution

    I doubt somebody will ever encounter such a problem in the field ;)
    and I guess, I know the teacher's expectation:

    Lets take array {0,1,2,...,n-2,n-1},
    The given one can be produced by replacing last two elements n-2 and n-1 with unknown p and q (less order)

    so, the sum of elements will be (n-1)n/2 + p + q - (n-2) - (n-1)
    the sum of squares (n-1)n(2n-1)/6 + p^2 + q^2 - (n-2)^2 - (n-1)^2

    Simple math remains:

      (1)  p+q = S1  
      (2)  p^2+q^2 = S2
    

    Surely you won't solve it as math classes teach to solve square equations.

    First, calculate everything modulo 2^32, that is, allow for overflow.
    Then check pairs {p,q}: {0, S1}, {1, S1-1} ... against expression (2) to find candidates (there might be more than 2 due to modulo and squaring)
    And finally check found candidates if they really are present in array twice.

    0 讨论(0)
  • 2020-11-28 07:13
    suppose array is
    
    a[0], a[1], a[2] ..... a[n-1]
    
    sumA = a[0] + a[1] +....+a[n-1]
    sumASquare = a[0]*a[0] + a[1]*a[1] + a[2]*a[2] + .... + a[n]*a[n]
    
    sumFirstN = (N*(N+1))/2 where N=n-3 so
    sumFirstN = (n-3)(n-2)/2
    
    similarly
    
    sumFirstNSquare = N*(N+1)*(2*N+1)/6 = (n-3)(n-2)(2n-5)/6
    
    Suppose repeated elements are = X and Y
    
    so X + Y = sumA - sumFirstN;
    X*X + Y*Y = sumASquare - sumFirstNSquare;
    
    So on solving this quadratic we can get value of X and Y.
    Time Complexity = O(n)
    space complexity = O(1)
    
    0 讨论(0)
  • 2020-11-28 07:14

    Since a range is specified, you can perform radix sort. This would sort your array in O(n). Searching for duplicates in a sorted array is then O(n)

    0 讨论(0)
  • 2020-11-28 07:15

    I have written a small programme which finds out the number of elements not repeated, just go through this let me know your opinion, at the moment I assume even number of elements are even but can easily extended for odd numbers also.

    So my idea is to first sort the numbers and then apply my algorithm.quick sort can be use to sort this elements.

    Lets take an input array as below

    int arr[] = {1,1,2,10,3,3,4,5,5,6,6};
    

    the number 2,10 and 4 are not repeated ,but they are in sorted order, if not sorted use quick sort to first sort it out.

    Lets apply my programme on this

    using namespace std;
    
    main()
    {
        //int arr[] = {2, 9, 6, 1, 1, 4, 2, 3, 5};
        int arr[] = {1,1,2,10,3,3,4,5,5,6,6};
    
        int i = 0;
    
        vector<int> vec;
    
        int var = arr[0];
        for(i = 1 ; i < sizeof(arr)/sizeof(arr[0]); i += 2)
        {
                var = var ^ arr[i];
    
                if(var != 0 )
                {
                    //put in vector
                    var = arr[i-1];
                    vec.push_back(var);
                    i = i-1;
                }
                var = arr[i+1];
        }
    
        for(int i = 0 ; i < vec.size() ; i++)
            printf("value not repeated = %d\n",vec[i]);
    
    }
    

    This gives the output:

    value not repeated= 2
    
    value not repeated= 10
    
    value not repeated= 4
    

    Its simple and very straight forward, just use XOR man.

    0 讨论(0)
  • 2020-11-28 07:17

    Check this old but good paper on the topic:

    • Finding Repeated Elements (PDF)
    0 讨论(0)
  • 2020-11-28 07:17

    Sorting the array would seem to be the best solution. A simple sort would then make the search trivial and would take a whole lot less time/space.

    Otherwise, if you know the domain of the numbers, create an array with that many buckets in it and increment each as you go through the array. something like this:

    int count [10];
    
    for (int i = 0; i < arraylen; i++) {
        count[array[i]]++;
    }
    

    Then just search your array for any numbers greater than 1. Those are the items with duplicates. Only requires one pass across the original array and one pass across the count array.

    0 讨论(0)
提交回复
热议问题