Problem overview
The function top_scorer receives scores, a HashMap<String, i32> from player names to scores, and returns the name of the player with the highest score. If several players share the highest score, it returns the one that comes first in alphabetical order. The map always has at least one player, and every score is between 0 and 100.
For {"Ana": 90, "Ben": 75, "Cara": 88} the answer is "Ana". For {"Zoe": 82, "Ana": 82} both players tie, so the answer is "Ana".
Approach
Keep the best player seen so far and compare every entry with it. This is the usual "running best" pattern, with one twist: the order of a HashMap is not fixed, so the code can't rely on which player comes first. That is why the tie rule matters. A player replaces the current best in two cases:
- their score is higher, or
- their score is equal and their name comes earlier alphabetically.
With both rules in place, the final answer is the same whatever order the loop visits the players in.
Step by step
- Start with an empty
best_name(String::new()) and abest_scoreof -1. Scores are never below 0, so the first player visited always beats -1. - Loop over
&scores, unpacking each entry into(name, score). The&borrows the map, sonameis a&Stringandscoreis a&i32. - Inside the loop, decide whether this player is better. Compare
*scorewithbest_score, and for a tie compare*namewithbest_nameusing<, which is true when the left string comes earlier alphabetically. - If so, store the new best:
name.clone()and*score. - After the loop, return
best_name.
The solution in Rust
impl Solution {
fn top_scorer(scores: HashMap<String, i32>) -> String {
let mut best_name = String::new();
let mut best_score = -1;
for (name, score) in &scores {
if *score > best_score || (*score == best_score && *name < best_name) {
best_name = name.clone();
best_score = *score;
}
}
return best_name;
}
}
Details worth knowing
- Why
clone(). The loop only borrows the names from the map, sonameis a reference.best_nameis aStringthat owns its text, so it needs its own copy. Assigning the reference directly does not compile: the compiler reportsexpected `String`, found `&String`. - Why
*scoreand*name. Both are references. The star reads the value behind each one so it can be compared withbest_scoreandbest_name. - The parentheses. The tie check only counts when the scores are equal, so
*score == best_score && *name < best_namegoes in parentheses and joins the first condition with||. - Alphabetical order. Strings compare by their characters, so
"Ana" < "Zoe"is true. Capital letters come before lowercase ones ("Ana" < "ana"is true too). The lesson's names are always a capital followed by lowercase letters, so this never causes trouble.
Trying it
Running the function on the lesson's examples gives:
{"Ana": 90, "Ben": 75, "Cara": 88} -> Ana
{"Zoe": 82, "Ana": 82} -> Ana
{"Max": 0} -> Max
{"Zoe": 0, "Ana": 0, "Max": 0} -> Ana
The single player with a score of 0 shows why the start value is -1 and not 0: with 0, a lone player scoring 0 would never replace the empty name, and the function would return an empty string.
Common mistakes
- Ignoring ties. Using only
*score > best_scorereturns whichever tied player the map happens to visit first, and that can change between runs. - Starting
best_scoreat 0. That breaks the case where the only top score is 0. - Using
<=or>=on scores. A tie must be decided by the name, not by who was visited last. - Forgetting the
&in the loop. The loop would take the map for itself, which is fine here only because the map isn't used again.
