Problem overview
The function secondLargest in class Solution receives three integers, A, B and C, and returns the one that is neither the largest nor the smallest, which is the middle value.
For A = 7, B = 3, C = 9 the sorted order is 3, 7, 9, so the answer is 7. For A = 12, B = 8, C = 3 the sorted order is 3, 8, 12, so the answer is 8.
The statement asks for O(1) time and O(1) extra space. With only three numbers, that is natural: the function does a fixed number of comparisons and stores nothing.
Approach: test each candidate
There are only three candidates. One of them must be the middle value, so the plan is to test A, then B, and to return C if neither fits.
A number is the middle value when it sits between the other two, inclusive. For A, that means the smaller of B and C is at most A, and A is at most the larger of B and C. Sorting the three numbers would also work, but a sort is more machinery than three numbers need, and the conditions above show the idea directly.
Using "less than or equal" instead of "less than" matters when values repeat. With A = 5, B = 5, C = 9, the sorted order is 5, 5, 9, and the middle value is 5. Both conditions hold for A because min(B, C) is 5, which equals A.
Step by step
- Check
A. Build one condition from two comparisons joined with&&: the smaller ofBandCis at mostA, andAis at most the larger of the two. If both hold, returnAat once. - Check
B. It is the same test with the roles changed: compareBagainst the smaller and larger ofAandC. - Return
C. If neitherAnorBis the middle value, thenCmust be. No third check is needed, and writing one would only add code that can never change the result.
The solution in Kotlin
class Solution {
fun secondLargest(A: Int, B: Int, C: Int): Int {
if (minOf(B, C) <= A && A <= maxOf(B, C)) {
return A
}
if (minOf(A, C) <= B && B <= maxOf(A, C)) {
return B
}
return C
}
}
Kotlin details worth knowing:
minOfandmaxOfare functions, not methods. They are part of the standard library, so you call them asminOf(B, C)with no import. They also accept three arguments, as inmaxOf(A, B, C).&&short-circuits. If the left comparison is false, Kotlin doesn't evaluate the right one. Here both sides are cheap, so it only affects readability.- The parameter names start with capitals. Kotlin convention prefers
a,bandc, but the lesson's tests call the function by position, and the namesA,B,Care what the editor gives you, so keep them. - The function body must return on every path. A function declared with return type
Intthat can reach the closing brace without returning doesn't compile. The finalreturn Cguarantees that this one always returns. Intcomparisons don't overflow. The solution only compares values and never adds or subtracts them, so evenInt.MAX_VALUEandInt.MIN_VALUEare safe inputs.
Complexity
Time: O(1). The function runs at most four minOf/maxOf calls and four comparisons, whatever the values are.
Space: O(1). It creates no arrays, lists or other structures that grow with the input.
Edge cases and common mistakes
- Equal values.
secondLargest(4, 4, 4)returns 4, andsecondLargest(9, 5, 5)returns 5. Using strict<in the conditions would skip the right candidate when two values tie. - Negative numbers. The comparisons work the same way:
secondLargest(-1, -5, -3)returns -3. - Swapping
minOfandmaxOf. If the smaller bound is written asmaxOf, the condition can almost never hold, and the function falls through toreturn Cfor the wrong inputs. - Returning the position instead of the value. The function returns the number itself, not "A" or its place in the sorted order.
- Checking only the top. Testing whether
Ais greater than one of the others is not enough. The middle value must be at least one number and at most another.
Testing
secondLargest(7, 3, 9)gives7.secondLargest(12, 8, 3)gives8.secondLargest(1, 2, 3)gives2, returned by the second check.secondLargest(3, 1, 2)gives2, the case whereCis the answer.secondLargest(5, 5, 9)gives5.