Problem overview
topScorer receives scores, a map[string]int from player names to scores, and returns the name of the player with the highest score. When several players share the top score, the name that comes first alphabetically wins.
With {"Ana": 90, "Ben": 75, "Cara": 88} the answer is "Ana". With {"Zoe": 82, "Ana": 82} both have 82, and "Ana" comes before "Zoe". With a single player, that player wins. The map always has at least one name, and every score is between 0 and 100.
Approach
Keep the best player seen so far and compare every entry against it. The starting values matter. Setting bestName to an empty string and bestScore to -1 works because no real score is below 0, so the first entry visited always beats the starting value.
A map has no fixed order in Go, so the loop may meet the players in any sequence. That is why the tie rule has to be part of the comparison: the answer must come out the same whichever player is visited first.
Step by step
- Declare
bestName := ""andbestScore := -1. - Loop with
for name, score := range scores. - Inside, test whether this player beats the best: a higher score, or an equal score with a smaller name. Strings compare with
<in alphabetical (byte) order, and the tie check goes in parentheses so it only applies when the scores are equal. - When the test is true, store the player's name and score as the new best.
- After the loop, return
bestName.
The solution in Go
func topScorer(scores map[string]int) string {
bestName := ""
bestScore := -1
for name, score := range scores {
if score > bestScore || (score == bestScore && name < bestName) {
bestName = name
bestScore = score
}
}
return bestName
}
The condition reads as "strictly higher, or tied and alphabetically earlier". Because && binds tighter than || in Go, the parentheses are not required, but they make the intent clear.
A trace of the idea on the first example, in the order the loop happens to meet the players (another order gives the same answer): Ana (90) beats -1, so she becomes the best. Ben (75) is lower and is skipped. Cara (88) is lower and is skipped. For the second example, if Zoe is met first she becomes the best with 82; then Ana ties on 82, and because "Ana" < "Zoe" is true she replaces Zoe. If Ana is met first, Zoe's tie check fails since "Zoe" < "Ana" is false, and Ana stays.
Testing
Running the function on the statement's examples gives:
{"Ana": 90, "Ben": 75, "Cara": 88} -> Ana
{"Zoe": 82, "Ana": 82} -> Ana
{"Max": 0} -> Max
The last one is why the start value is -1 and not 0: a lone player with a score of 0 must still replace the empty bestName.
Common mistakes
- Starting
bestScoreat 0. A player with 0 points would never beat it, and the function would return an empty string. - Ignoring the tie rule. Using only
score > bestScorekeeps whichever tied player the random map order meets first, so the result can change from run to run. - Dropping the parentheses in the wrong place. The name comparison must apply only when the scores are equal; comparing names on its own would pick the alphabetically first player regardless of score.
- Returning the score. The function returns the name, a
string.
