I'm not sure what the exact definition of "comparator" is, the way they're using it. But assuming that Math.min
and Math.max
don't count as comparators, here's a way to compute it using no comparisons or comparators:
public static int thirdLargest(int a, int b, int c, int d) {
int min = Math.min(a, Math.min(b, Math.min(c,d)));
int offset = min + 1 - Integer.MIN_VALUE;
a -= offset;
b -= offset;
c -= offset;
d -= offset;
min = Math.min(a, Math.min(b, Math.min(c,d)));
return min + offset;
}
Computing the third largest number is the same as computing the second smallest number. The trick in this code is that it computes the smallest number, then subtracts from each number the exact offset needed to make the smallest number wrap around and become Integer.MAX_VALUE, while not wrapping around for the other values. The smallest of the remaining numbers is now the second smallest of the original numbers, minus the offset, which we'll add back.
However, I'll concede that this only works if all four numbers are distinct--or, at least, if the lowest two numbers are distinct. It fails if you give it a=1, b=1, c=2, d=3--it outputs 2 instead of 1. At least this should get you points for your problem-solving skill, which is what I assume the question is intended to find out. It had better not be to find out how you would actually solve this in a production situation, because putting restrictions like this on production code (no arrays) would be lunacy.
EDIT:
Here's another solution. There's one comparison in the code, but it's in a method that's executed three times, so that should count as three comparisons.
public static int thirdLargest(int a, int b, int c, int d) {
if (isThirdLargest(a, b, c, d)) {
return a;
}
if (isThirdLargest(b, a, c, d)) {
return b;
}
if (isThirdLargest(c, a, b, d)) {
return c;
}
return d;
}
public static boolean isThirdLargest(int a, int b, int c, int d) {
int z = 3 + ((b - a) >> 31) + ((c - a) >> 31) + ((d - a) >> 31);
// z = number of other parameters that are >= a. Note that all of the
// shift operations will return either 0 or -1.
int y = 3 + ((a - b) >> 31) + ((a - c) >> 31) + ((a - d) >> 31);
// y = number of other parameters that are <= a
int x = -y >>> 31;
// x = 1 if there are any other parameters <= a, 0 if not. Note that
// x can be 0 only if z == 3.
int w = z & (x << 1);
// This will be 2 if a is the third largest. If z == 2, then x == 1
// and w will be 2. If z == 3, and x == 1, that means that a is the
// smallest but is equal to at least one of the other parameters;
// therefore a is also the third largest. But if x == 0, a is
// strictly smaller than all other parameters and is therefore not the
// third largest.
return w == 2;
}
Note: This may suffer from overflow problems, if there are two numbers that differ by 231 or greater. Converting all the parameters to long
should avoid the problem (also all the 31's would be changed to 63), but I haven't tested it.