Question 1
A magic index in an array A[l.. .n-l] is defined to be an index such that A[i] = i.
Given a sorted array of distinct integers, write a method to find a magic index, if one exists, in array A.
Question 2
FOLLOW UP: What if the values are not distinct?
Solution
This is a difficult binary search question!
Question 1 is slightly easier: we simplyl use binary search, and we are able to discard half of the array each time.
- if (array[mid] > mid), then we discard the right half.
- if (array[mid] < mid), then we discard the left half.
Question 2 is difficult. We cannot discard half of the input any more. Instead, we discard a range between (mid) and (array[mid]). Then check left and right part seperately.
So, I wrote the following code:
int mid = left + (right - left) / 2;
if (array[mid] == mid) {
return mid;
} else {
int smaller = Math.min(array[mid], mid);
int larger = Math.max(array[mid], mid);
int leftResult = helper(array, left, smaller);
if (leftResult != -1) {
return leftResult;
} else {
return helper(array, larger, right);
}
}
This becomes an endless loop. We did not discard point ‘mid’ in the code above. The correct code is posted below.
Code
code for non-duplicate input
public static int myAnswerNonDup(int[] array) {
int len = array.length;
return helper(array, 0, len - 1);
}
public static int helper(int[] array, int left, int right) {
if (right < left) {
return -1;
}
int mid = left + (right - left) / 2;
if (array[mid] == mid) {
return mid;
} else if (array[mid] < mid) {
// discard all element to the left of array[mid]
return helper(array, mid + 1, right);
} else {
return helper(array, left, mid - 1);
}
}
code for have-duplicate input
public static int myAnswerWithDup(int[] array) {
int len = array.length;
return helper(array, 0, len - 1);
}
public static int helper(int[] array, int left, int right) {
if (right < left) {
return -1;
}
int mid = left + (right - left) / 2;
if (array[mid] == mid) {
return mid;
} else {
int smaller = 0;
int larger = 0;
if (array[mid] < mid) {
smaller = array[mid];
larger = mid + 1;
} else if (array[mid] > mid) {
smaller = mid - 1;
larger = array[mid];
}
int leftResult = helper(array, left, smaller);
if (leftResult != -1) {
return leftResult;
} else {
return helper(array, larger, right);
}
}
}