Problem overview
The method topScorer receives scores, a HashMap<String, Integer> from players' names to their scores, and returns the name of the player with the highest score. If several players share the highest score, the answer is the name that comes first alphabetically.
For {"Ana": 90, "Ben": 75, "Cara": 88} the answer is Ana. For {"Zoe": 82, "Ana": 82} both have 82, and Ana comes before Zoe, so the answer is Ana. A map with one player, {"Max": 0}, returns Max. The map always has at least one name, and every score is from 0 to 100.
Approach
Keep the best player seen so far and compare every entry with it. A map has no fixed order, so the code can't assume which entry comes first. That is why the tie rule has to be written into the comparison itself, rather than relying on the order of visiting.
The starting values are an empty name and a score of -1. Every real score is at least 0, so the first player visited always beats -1 and replaces the starting values.
Step by step
- Set
bestNameto an empty string andbestScoreto -1. - Loop over
scores.entrySet(), with aMap.Entry<String, Integer>namedentry. - Read the key into
nameand the value intoscore, so the comparison below is easy to read. - Check whether this player is better: a higher score, or an equal score and a name that comes first.
- If so, store the name and the score as the new best.
- After the loop, return
bestName.
The solution in Java
class Solution {
public String topScorer(HashMap<String, Integer> scores) {
String bestName = "";
int bestScore = -1;
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
String name = entry.getKey();
int score = entry.getValue();
if (score > bestScore || (score == bestScore && name.compareTo(bestName) < 0)) {
bestName = name;
bestScore = score;
}
}
return bestName;
}
}
Two details are worth knowing:
name.compareTo(bestName)returns a negative number whennamecomes beforebestNamein alphabetical order, zero when they are equal and a positive number otherwise. The names here are a capital letter followed by lowercase letters, so plain alphabetical order is whatcompareTogives.- The parentheses around the tie check matter. The tie only counts when the two scores are equal, so
score == bestScoreand the name test belong together. In Java&&binds tighter than||, and the brackets make that visible.
It is worth tracing the second example. If Zoe is visited first, she becomes the best, with 82. When Ana arrives with the same score, the first part of the condition is false, but the second part is true, because "Ana".compareTo("Zoe") is negative. So Ana replaces her. If Ana is visited first, Zoe fails both parts and is skipped. Either order ends with Ana.
Edge cases and common mistakes
- Forgetting the tie rule. If the condition is only
score > bestScore, the first entry with the top score wins, and for{"Zoe": 82, "Ana": 82}that depends on the map's internal order. The code might return either name. - Starting
bestScoreat 0. A player with 0 points, likeMaxin the last example, would never beat it, and the method would return an empty string. Starting at -1 avoids that. - Comparing names with
==. Strings are objects, so==compares references. Useequalsfor equality andcompareTofor order. - Returning the score instead of the name. The method returns a
String.
Testing
Running the solution on the three examples gives:
Ana
Ana
Max
