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

后端 未结 15 1985
梦如初夏
梦如初夏 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

    I have an algorithm which works in log(N/C)*log(K), where K is the length of maximum same-value range, and C is the length of range being searched for.

    The main difference of this algorithm from most posted before is that it takes advantage of the case where all same-value ranges are short. It finds boundaries not by binary-searching the entire array, but by first quickly finding a rough estimate by jumping back by 1, 2, 4, 8, ... (log(K) iterations) steps, and then binary-searching the resulting range (log(K) again).

    The algorithm is as follows (written in C#):

    // Finds the start of the range of equal numbers containing the index "index", 
    // which is assumed to be inside the array
    // 
    // Complexity is O(log(K)) with K being the length of range
    static int findRangeStart (int[] arr, int index)
    {
        int candidate = index;
        int value = arr[index];
        int step = 1;
    
        // find the boundary for binary search:
        while(candidate>=0 && arr[candidate] == value)
        {
            candidate -= step;
            step *= 2;
        }
    
        // binary search:
        int a = Math.Max(0,candidate);
        int b = candidate+step/2;
        while(a+1!=b)
        {
            int c = (a+b)/2;
            if(arr[c] == value)
                b = c;
            else
                a = c;
        }
        return b;
    }
    
    // Finds the index after the only "odd" range of equal numbers in the array.
    // The result should be in the range (start; end]
    // The "end" is considered to always be the end of some equal number range.
    static int search(int[] arr, int start, int end)
    {
        if(arr[start] == arr[end-1])
            return end;
    
        int middle = (start+end)/2;
    
        int rangeStart = findRangeStart(arr,middle);
    
        if((rangeStart & 1) == 0)
            return search(arr, middle, end);
        return search(arr, start, rangeStart);
    }
    
    // Finds the index after the only "odd" range of equal numbers in the array
    static int search(int[] arr)
    {
        return search(arr, 0, arr.Length);
    }
    

提交回复
热议问题