Problem overview
The method TopScorer receives scores, a Dictionary<string, int> from player names to scores. It returns the name of the player with the highest score. When several players share the top score, it returns the name that comes first alphabetically.
For {"Ana": 90, "Ben": 75, "Cara": 88} the answer is Ana, because 90 is the highest score. For {"Zoe": 82, "Ana": 82} both players have 82, so the alphabetical rule picks Ana. A dictionary with only {"Max": 0} returns Max.
Approach
Walk through the entries once and remember the best player seen so far: a name and a score. For each entry, ask whether this player beats the best one. If so, replace the best.
A player beats the best when the score is higher, or when the score is equal and the name comes first alphabetically. A dictionary promises no order, so the tie rule has to be in the comparison itself. Otherwise the answer would depend on which name the loop happened to meet first.
The starting values need care. All scores are at least 0, so a starting score of -1 is beaten by the very first player. The starting name is an empty string.
Step by step
- Set up the best so far:
bestNameas an empty string andbestScoreas -1. - Loop over the entries with
foreach (var pair in scores). - Read the key and value into
nameandscore, so the comparison is easy to read. - Test whether this player wins: a higher score, or an equal score and a name that sorts earlier.
name.CompareTo(bestName) < 0is true whennamecomes beforebestName. - Update both variables inside the
if. - Return
bestNameafter the loop.
The solution in C#
class Solution {
public string TopScorer(Dictionary<string, int> scores) {
string bestName = "";
int bestScore = -1;
foreach (var pair in scores) {
string name = pair.Key;
int score = pair.Value;
if (score > bestScore || (score == bestScore && name.CompareTo(bestName) < 0)) {
bestName = name;
bestScore = score;
}
}
return bestName;
}
}
Run on the three examples, it returns:
Ana
Ana
Max
The details worth knowing:
var pairis aKeyValuePair<string, int>;KeyandValueare its properties.CompareToreturns a negative number, zero or a positive number, so test it against 0 rather than against -1.- The parentheses around the tie check matter:
&&binds tighter than||in C#, but the parentheses make the intent clear to the reader.
Why the tie rule works
Think of the loop as keeping one champion. Each new entry challenges the champion, and the challenger wins only if the score is strictly higher, or the score is equal and the name sorts earlier. Both conditions are decided by the two entries alone, never by their position in the dictionary. That is why any visiting order ends with the same champion: the "best" entry is the maximum under a fixed ranking (score first, then name), and a maximum does not depend on the order you scan in.
For {"Zoe": 82, "Ana": 82} there are two possible visiting orders. If Zoe comes first, she becomes the champion with 82, then Ana challenges with an equal score and a name that sorts earlier, so she takes over. If Ana comes first, Zoe's challenge fails the name test. Both orders return Ana.
Edge cases and common mistakes
- Ties. With
{"Ana": 82, "Zoe": 82}and{"Zoe": 82, "Ana": 82}the answer isAnaboth times, because the rule never looks at the order of the entries. - A top score of 0. With
{"Max": 0}, a startingbestScoreof 0 would never be beaten, and an empty name never sorts after "Max", so the method would return an empty string. Starting at -1 avoids this. - Returning the score. The method returns the name, a
string, not the number. - Indexing the dictionary by position.
scores[0]is a lookup of the key 0, not the first entry, and it doesn't compile for string keys.
