Visualizing the steps taken can be done with a slight modification to STEPPER
:
private static final BiFunction<int[], Integer, Integer> STEPPER = (sorted, i) -> {
int r = Arrays.binarySearch(sorted, i, sorted.length, sorted[i] + 1);
r = r < 0 ? Math.abs(r + 1) : r;
System.out.printf("DEBUG: current (index = %d, value = %d); "
+ "next (index = %d, value = %s)%n",
i, sorted[i], r,
r >= sorted.length ? "END" : sorted[r]);
return r;
};
Given this example:
countUnique(new int[]{0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 4, 4, 4, 5, 5, 5, 5, 5});
// Output
DEBUG: current (index = 0, value = 0); next (index = 4, value = 1)
DEBUG: current (index = 4, value = 1); next (index = 7, value = 2)
DEBUG: current (index = 7, value = 2); next (index = 11, value = 4)
DEBUG: current (index = 11, value = 4); next (index = 14, value = 5)
DEBUG: current (index = 14, value = 5); next (index = 19, value = END)
Input(19): [0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 4, 4, 4, 5, 5, 5, 5, 5]
The answer is the number of DEBUG
lines printed, i.e. 5
. It works by jumping across any indices of the numbers 0 -> 1 -> 2 -> 4 -> 5
. The any index part is a known effect from the method's Javadoc:
If the range contains multiple elements with the specified value, there is no guarantee which one will be found.
This still suffices for our usage here as we only need to hit any of the next larger number. Also, since 3
is not present in the list, 4
is returned after 2
, and this is where the check for r < 0
is required to convert the result of Arrays.binarySearch()
to a positive, usable index.