First occurrence in a binary search
If your data is all integral, then this hack can help. It uses a float array to store values.
float array[]; //contains all integral values
int searchValue;
int firstIndex = -(binarySearch(array, (float)searchValue - 0.5F) + 1);
Basically what it does is find the insertion index of a value in between your search value and the integer before it. Since all values are integral, it finds the first occurrence of the search value.
Also this runs is log(n) time.
Example:
import java.util.Arrays;
public class BinarySearch {
// considering array elements are integers
float ar[] = new float[] { 1, 2, 3, 3, 4, 4, 5, 9, 9, 12, 12 };
public void returnFirstOccurrence(int key) {
int firstIndex = -(Arrays.binarySearch(ar, key - 0.5F) + 1);
if (ar[firstIndex] != key)
System.out.println("Key doesn't exist");
else
System.out.println("First index of key is " + firstIndex);
}
public static void main(String Args[]) throws Exception {
new BinarySearch().returnFirstOccurrence(9);
}
}
OUTPUT: 7
p.s: I've used this trick on several coding contests and it nicely worked everytime.
An addition to Jon Skeets post:
The potential faster implementation is actually not hard to implement and adds only 2 lines of code, here is how I'd do it:
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else if (low != mid) //Equal but range is not fully scanned
high = mid; //Set upper bound to current number and rescan
else //Equal and full range is scanned
return mid;
Having found a matching value, you basically need to walk up the collection until you find an entry which doesn't match.
You could potentially make it faster by fetching the index of a key immediately lower than the one you were looking for, then do a binary chop between the two - but I'd probably go for the simpler version, which is likely to be "efficient enough" unless you've got a really large number of equal entries.