Problem overview
The method secondLargest receives three numbers, A, B and C, and returns the one in the middle when they are ordered by size. For 7, 3, 9 the order is 3, 7, 9, so the answer is 7. For 12, 8, 3 the answer is 8.
The task asks for O(1) time and O(1) space. With only three values, a few comparisons are enough: no sorting and no array are needed.
Approach: test each candidate
The answer is one of three values, so test them in turn. A number is the second largest when it is not below the smaller of the other two and not above the larger of the other two. In other words, it sits between them. For A, the condition is Math.min(B, C) <= A && A <= Math.max(B, C).
If A passes, return it. Otherwise test B the same way against A and C. If neither passes, C must be the answer, so it needs no test. Exactly one of the three numbers is the middle one when the values are distinct, so ruling out two leaves the third.
Work through A = 7, B = 3, C = 9. The smaller of B and C is 3 and the larger is 9. Since 3 <= 7 <= 9, A is in the middle and the method returns 7. With A = 12, B = 8, C = 3, the range for A is 3 to 8 and 12 is outside it. For B, the other two are 12 and 3, and 3 <= 8 <= 12 holds, so the method returns 8.
Step by step
- Check
A. Write anifwhose condition has two parts joined by&&: the smaller ofBandCis less than or equal toA, andAis less than or equal to the larger of them.Math.minandMath.maxcompute these. Inside, returnA. - Check
B. Repeat withBagainstAandC, and returnBwhen it fits. - Return
C. IfAandBfailed,Cis what is left, so the method returns it without another check.
The solution in TypeScript
class Solution {
secondLargest(A: number, B: number, C: number): number {
if (Math.min(B, C) <= A && A <= Math.max(B, C)) {
return A;
}
if (Math.min(A, C) <= B && B <= Math.max(A, C)) {
return B;
}
return C;
}
}
Language notes:
Math.minandMath.maxare built-in functions that take any number of arguments and return the smallest or largest. They are called on theMathobject, not on the numbers.- Parameter names. The capital letters
A,BandCare ordinary parameter names. TypeScript convention is lowerCamelCase, but here they match the lesson. - Chained comparisons don't exist. In some languages,
x <= A <= ymeans "A between x and y". In TypeScript it parses as(x <= A) <= y, comparing a boolean to a number, which the compiler reports as an error. Two comparisons joined by&&are needed. - Annotations are erased.
numberis checked only by the compiler.
Complexity
The method makes a fixed number of comparisons and calls to Math.min and Math.max, so it runs in O(1) time and uses O(1) extra space.
Edge cases and common mistakes
- Duplicates. With
5, 5, 3the sorted order is 3, 5, 5, and the second largest is 5. The method returns 5, because the comparisons use<=. With2, 2, 2it returns 2. With strict<instead,5, 5, 3would return 3, which is wrong. - Negative numbers. The method uses only comparisons, so
-1, -5, -3gives-3. - Any position. The answer can be
A,BorC. Test all three:7, 3, 9(answer isA),12, 8, 3(answer isB) and9, 3, 7(answer isC). - Using
sort()on an array.[A, B, C].sort()with no comparator sorts as strings, so[10, 9, 1]becomes[1, 10, 9]. A numeric sort needs(x, y) => x - y. The comparison approach in this lesson avoids the issue and the allocation.
Testing
secondLargest(7, 3, 9)should give7.secondLargest(12, 8, 3)should give8.secondLargest(9, 3, 7)should give7.secondLargest(5, 5, 3)should give5.secondLargest(-1, -5, -3)should give-3.