Problem overview
The method leaderboard gets an array players. Each player is a tuple [string, number]: a name and a score. It returns the names only, from the highest score to the lowest. Players with the same score go in alphabetical order of their names. There are 1 to 100 players, scores run from 0 to 1000, and no two players share a name.
For [["Ava", 30], ["Ben", 25], ["Cy", 40]] the result is ["Cy", "Ava", "Ben"]. For [["Mia", 50], ["Leo", 70], ["Ava", 50]] it is ["Leo", "Ava", "Mia"]: Leo leads with 70, and Ava comes before Mia among the two 50s. For [["Zoe", 0]] it is ["Zoe"].
Approach
Two steps: sort the pairs, then collect the names.
The sort uses a compare function with two rules. In a pair, index 0 is the name and index 1 is the score. If the scores differ, the higher score goes first, so return b[1] - a[1]. This is negative when a has more points, which puts a first. If the scores are equal, return a[0].localeCompare(b[0]), which orders the names from A to Z.
After the sort the pairs are in the right order, so a loop that pushes each name into a new array produces the answer.
Step by step
- Call
players.sortwith a function ofaandbwhose first rule returnsb[1] - a[1]when the scores differ. - Add the second rule for equal scores:
a[0].localeCompare(b[0]). - Start an empty
string[]callednames. - Loop over
playerswithfor (const [name, score] of players), which unpacks each pair into two constants. - Push
nameontonamesinside the loop. - Return
namesafter the loop.
The solution in TypeScript
class Solution {
leaderboard(players: [string, number][]): string[] {
players.sort((a, b) => {
if (a[1] !== b[1]) {
return b[1] - a[1];
}
return a[0].localeCompare(b[0]);
});
let names: string[] = [];
for (const [name, score] of players) {
names.push(name);
}
return names;
}
}
The type [string, number][] is an array of tuples. The destructuring in the loop, const [name, score], names the two parts of the pair. The loop never uses score, and that is fine: TypeScript does not flag unused variables here.
Notice the direction of each subtraction. For ascending order you write a - b; for descending order, b - a. The name rule is ascending, so it keeps a on the left.
A compare function that returns b[1] - a[1] for the score and a text comparison for the name is the usual way to sort by a main key with a tie-break. Sorting changes the players array in place; the method returns a new array of names.
Tracing the second example
With [["Mia", 50], ["Leo", 70], ["Ava", 50]], comparing Leo with Mia: the scores differ, so b[1] - a[1] decides, and Leo's 70 puts him first. Comparing Ava with Mia: both have 50, so localeCompare decides, and "Ava" comes before "Mia". The sorted pairs are Leo, Ava, Mia, and the loop collects ["Leo", "Ava", "Mia"]. The tests print such a list as values separated by spaces: Leo Ava Mia.
Testing
| players | Result |
|---|---|
[["Ava", 30], ["Ben", 25], ["Cy", 40]] | ["Cy", "Ava", "Ben"] |
[["Mia", 50], ["Leo", 70], ["Ava", 50]] | ["Leo", "Ava", "Mia"] |
[["Zoe", 0]] | ["Zoe"] |
Common mistakes
- Sorting by score ascending.
a[1] - b[1]puts the lowest score first; the leaderboard needsb[1] - a[1]. Sorting the example[["Mia", 50], ["Leo", 70], ["Ava", 50]]that way gives Mia, Ava, Leo. - Skipping the tie rule. With only the score rule, tied players stay in their old order, so Mia would come before Ava.
- Mixing up the indexes.
a[0]is the name,a[1]the score. Subtracting names is reported as a type error, and at run time it givesNaN, which does not order anything. - Returning the pairs. The method returns names only.
