简体   繁体   中英

Finding the only repeating element in sorted array

I'm aware of the XOR trick to find the non-repeating element in a sorted array (which has been asked before):

public int singleNumber(int[] nums) {
    int result = 0; 
    for (int i = 0; i < nums.length; i++) {
        result = result ^ nums[i]; 
    }
    return result; 
}

But how can we use the same logic to do the opposite?

More specifically: Consider a sorted array where each element but one occurs only once, how do we find the one element that repeats in O(1) space?

The XOR trick is only neat if you want to discard even numbers of repetitions. One way of looking at it is to say that the xor of all the elements of an array is the xor of the oddly-repeating elements of that array ; so that, if there is only one oddly-repating element, you can find it in that way. And you do not need the array to be sorted at all to do so:

// could also have called it xorOfOddlyRepeatingIntsInArray(int[] a)
public static int findSingleNonEvenlyRepetingIntInUnsortedArray(int[] a) {
  int x = 0;
  for (int i: a) x ^= i;
  return x;
}

For what you are asking, both of these fragments find the repeat element in a sorted array in O(1) space and O(n) time:

public static int findSingleRepeatingIntInSortedArray1(int[] a) {
  for (int i=0; i<a.length-1; i++) if (a[i] == a[i+1]) return a[i];
  return -1;
}

public static int findSingleRepeatingIntInSortedArray2(int[] a) {
  for (int i=0; i<a.length-1; i++) if ((a[i] ^ a[i+1]) == 0) return a[i];
  return -1;
}

But you should prefer version 1, as a[i] == a[i+1] is much more readable than (a[i] ^ a[i+1]) == 0 , or (a[i] - a[i+1]) == 0 , or (a[i] & a[i+1]) == a[i] , or other arcane variants to check for equality. Xor buys you nothing in this case .

For laughs and giggles, this code finds the single repeating value in O(1) space in an unsorted array:

 public static int findSingleRepeatingIntInSortedArray3(int[] a) {
    for (int i=0; i<a.length; i++) {
       for (int j=i+1; j<a.length; j++) {
          if (a[i] == a[j]) return a[i];
       }
    }
    return 0;
 }

Yes, it is O(n^2) time , and there are faster ways of finding the first repeated element (sorting comes to mind) - but it is a valid answer to the question.

I think someone removed the comment which was using XOR. Here it is:

    private int returnNumber(int[] nums) {
    int result = 0;
    for (int i = 1; i < nums.length; i++) {
        if ((nums[i] ^ nums[i - 1]) == 0) {
            result = nums[i];
            break;
        }
    }
    return result;
}

I am really not sure if this uses O(1) or not.

I did not manage to find an XOR-based solution, but this surprisingly simple solution does the trick in-place.

public static int getRepeatingValue(int[] nums) {
    for (int i = 1; i < nums.length; i++) {
        if (nums[i] == nums[i - 1]) {
            return nums[i]; 
        }
    }
    return -1; 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM