How can I find a number which occurs an odd number of times in a SORTED array in O(n) time?

后端 未结 15 1988
梦如初夏
梦如初夏 2021-01-30 10:31

I have a question and I tried to think over it again and again... but got nothing so posting the question here. Maybe I could get some view-point of others, to try and make it w

相关标签:
15条回答
  • 2021-01-30 11:19

    Take the middle element e. Use binary search to find the first and last occurrence. O(log(n)) If it is odd return e. Otherwise, recurse onto the side that has an odd number of elements [....]eeee[....]

    Runtime will be log(n) + log(n/2) + log(n/4).... = O(log(n)^2).

    0 讨论(0)
  • 2021-01-30 11:21

    Use a hash table

    For each element E in the input set
        if E is set in the hash table
             increment it's value
        else        
             set E in the hash table and initialize it to 0
    
    For each key K in hash table
        if K % 2 = 1
            return K
    

    As this algorithm is 2n it belongs to O(n)

    0 讨论(0)
  • 2021-01-30 11:21

    Try this:

    int getOddOccurrence(int ar[], int ar_size)
    {
         int i;
         int xor = 0; 
         for (i=0; i < ar_size; i++)     
            xor = xor ^ ar[i];
    
         return res;
    }
    

    XOR will cancel out everytime you XOR with the same number so 1^1=0 but 1^1^1=1 so every pair should cancel out leaving the odd number out.

    0 讨论(0)
  • 2021-01-30 11:25

    You can use this algorithm:

    int GetSpecialOne(int[] array, int length)
    {
       int specialOne = array[0];
    
       for(int i=1; i < length; i++)
       {
          specialOne ^= array[i];
       }
       return specialOne;
    }
    

    Solved with the help of a similar question which can be found here on http://www.technicalinterviewquestions.net

    0 讨论(0)
  • 2021-01-30 11:27

    This answer is in support of the answer posted by "throwawayacct". He deserves the bounty. I spent some time on this question and I'm totally convinced that his proof is correct that you need Ω(log(n)^2) queries to find the number that occurs an odd number of times. I'm convinced because I ended up recreating the exact same argument after only skimming his solution.

    In the solution, an adversary creates an input to make life hard for the algorithm, but also simple for a human analyzer. The input consists of k pages that each have k entries. The total number of entries is n = k^2, and it is important that O(log(k)) = O(log(n)) and Ω(log(k)) = Ω(log(n)). To make the input, the adversary makes a string of length k of the form 00...011...1, with the transition in an arbitrary position. Then each symbol in the string is expanded into a page of length k of the form aa...abb...b, where on the ith page, a=i and b=i+1. The transition on each page is also in an arbitrary position, except that the parity agrees with the symbol that the page was expanded from.

    It is important to understand the "adversary method" of analyzing an algorithm's worst case. The adversary answers queries about the algorithm's input, without committing to future answers. The answers have to be consistent, and the game is over when the adversary has been pinned down enough for the algorithm to reach a conclusion.

    With that background, here are some observations:

    1) If you want to learn the parity of a transition in a page by making queries in that page, you have to learn the exact position of the transition and you need Ω(log(k)) queries. Any collection of queries restricts the transition point to an interval, and any interval of length more than 1 has both parities. The most efficient search for the transition in that page is a binary search.

    2) The most subtle and most important point: There are two ways to determine the parity of a transition inside a specific page. You can either make enough queries in that page to find the transition, or you can infer the parity if you find the same parity in both an earlier and a later page. There is no escape from this either-or. Any set of queries restricts the transition point in each page to some interval. The only restriction on parities comes from intervals of length 1. Otherwise the transition points are free to wiggle to have any consistent parities.

    3) In the adversary method, there are no lucky strikes. For instance, suppose that your first query in some page is toward one end instead of in the middle. Since the adversary hasn't committed to an answer, he's free to put the transition on the long side.

    4) The end result is that you are forced to directly probe the parities in Ω(log(k)) pages, and the work for each of these subproblems is also Ω(log(k)).

    5) Things are not much better with random choices than with adversarial choices. The math is more complicated, because now you can get partial statistical information, rather than a strict yes you know a parity or no you don't know it. But it makes little difference. For instance, you can give each page length k^2, so that with high probability, the first log(k) queries in each page tell you almost nothing about the parity in that page. The adversary can make random choices at the beginning and it still works.

    0 讨论(0)
  • 2021-01-30 11:27

    Assume indexing start at 0. Binary search for the smallest even i such that x[i] != x[i+1]; your answer is x[i].

    edit: due to public demand, here is the code

    int f(int *x, int min, int max) {
      int size = max;
      min /= 2;
      max /= 2;
      while (min < max) {
        int i = (min + max)/2;
        if (i==0 || x[2*i-1] == x[2*i])
          min = i+1;
        else
          max = i-1;
      }
      if (2*max == size || x[2*max] != x[2*max+1])
        return x[2*max];
      return x[2*min];
    }
    
    0 讨论(0)
提交回复
热议问题