Skip to content

Practice problem

Top Three Scores

Medium

Solve in Python or JavaScript · graded against 2 sample tests and a hidden test set in your browser · Published

The Bug Report

The program reads a line of scores and prints the three highest, highest first. It runs, it always prints exactly three values separated by spaces, and every value it prints really did come from the input. The three it picks are sometimes the wrong three, and in the wrong order.

Input that shows the problem

Input
5
9 100 25 7 80

What the program prints

Output
9 80 7

What it should print

Output
100 80 25

The largest score in the input is 100 and the program does not mention it, while printing 7 — the smallest score — as though it were in the top three. Notice what it did keep: 9, 80 and 7. A lot of inputs come out perfectly right, and the ones that go wrong all seem to mix scores of different lengths.

Input Format

The input has exactly two lines:

  • Line 1: a single integer n, the number of scores (at least 3).
  • Line 2: n integers separated by single spaces, the scores themselves.

Output Format

Print one line containing three integers separated by single spaces: the three highest scores, largest first. When scores repeat, print the repeats — three scores of 9 print as 9 9 9.

How to Debug It

The report mentions that the wrong answers seem to involve scores of different lengths, and that is worth confirming before anything else, because if it holds it rules out half the program. Build two inputs that differ in that one respect: a count line of 3 followed by 1 2 3, then a count line of 3 followed by 9 10 11. The first has all single-digit scores, the second mixes widths. Run both. If the all-single-digit one is right and the mixed one is wrong, the slicing and the reversing are working fine on both — the same three lines of code ran either way — and the difference has to be in the order the values are in by the time they get sliced.

So inspect that order directly rather than inferring it. Print the list on the line right after it is sorted, before -3 or slice(-3) touches it. Use the failing sample. What comes back will be in an order, consistently, and it will not be smallest-to-largest. Find where 9 sits relative to 100 in that output; if 9 is the greatest thing in the list, ask what comparison could possibly reach that conclusion.

The answer gives you a one-sentence hypothesis about what the sort thinks it is comparing. Test it cheaply before changing the program: sort ["9", "100", "25"] as text by hand, character by character, and see whether you reproduce the order the program produced. When it matches, change one thing — how the sort compares two values — leaving the slice and the reverse exactly as they are. Then re-run the second sample, all single digits, which was correct before and must stay correct, plus a case with duplicates such as a count line of 4 followed by 11 2 11 2.

What Was Wrong

Both versions sorted the scores as text instead of as numbers, for slightly different reasons — and the reasons are worth knowing separately, because they are two of the most common ways this happens.

In JavaScript, the scores really were numbers: .map(Number) converted them on the way in. The problem is sort() called with no arguments. Its default behaviour is not to compare numerically; it converts each element to a string and sorts by the resulting text in code-unit order. So [9, 100, 25, 7, 80] becomes [100, 25, 7, 80, 9], because "100" starts with '1' and "9" starts with '9'. Taking the last three of that and reversing gives 9 80 7.

In Python, sorted compares whatever it is given, and it was given strings: input().split() returns a list of text pieces and nothing ever converted them. sorted(["9", "100", "25", "7", "80"]) compares text the same way, producing the same order and the same wrong answer.

The fix in each language is to tell the sort to compare by numeric value:

Python
ordered = sorted(scores, key=int)
JavaScript
const ordered = [...scores].sort((a, b) => a - b);

The Python version keeps the values as strings — handy, since " ".join(...) needs strings — but orders them by int(...), which is what key is for. The JavaScript comparator returns a negative number, zero, or a positive number, which is the contract sort expects, and subtraction satisfies it for ordinary numbers. Both leave the slice and the reverse untouched, because those two steps were never wrong.

Common Mistakes

  • Writing the JavaScript comparator as (a, b) => a > b. sort needs a number back, not a boolean. true and false collapse to 1 and 0, so the comparator can never say "a comes first", and the result is an order that depends on the engine's sorting algorithm rather than on the data. Return a - b.
  • Fixing Python by converting to int and forgetting the output. Once the list holds integers, " ".join(...) raises a TypeError because it only joins strings. Either sort by key=int and keep the strings, or convert to integers and convert back when printing — but do decide which, rather than finding out from a traceback.
  • Assuming the sort is fine because the answer was right the last five times. Every score being the same width makes text order and numeric order agree, so a whole test suite of single-digit or equal-length values will pass over this bug without a murmur. The inputs that catch it are the ones that mix widths, which is why they belong in the tests on purpose.

Sample tests

Sample 1

Input

5
9 100 25 7 80

Expected output

100 80 25

Sorted by value the scores run 7, 9, 25, 80, 100, so the top three highest-first are 100, 80 and 25.

Sample 2

Input

4
4 9 7 2

Expected output

9 7 4

Every score here is a single digit, which — for reasons the bug report gets into — is exactly when the broken program looks correct.

Your solution

Run tries the first sample. Submit grades against every sample and the hidden tests. Your code is saved in this browser as you go. This problem accepts more than one language: pick yours above the editor, and each keeps its own work while this page is open.

Solve inYour work in each language is kept while this page is open.
Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

More problems

All practice problems →