Most Frequent Character

Most Frequent Character

Given a string, return the character that appears most frequently, as a one-character string. If several characters tie for the highest count, return the one that appears first in the string.

mostFrequentChar(s)

Examples

mostFrequentChar("abccccdd")  // → "c"
mostFrequentChar("hello")     // → "l"
mostFrequentChar("aaa")       // → "a"
mostFrequentChar("xyzx")      // → "x"

Walkthrough

Thinking it through

You need two things at once: which character shows up most, and — if there's a tie — which of the tied characters appeared first. Tracking both in a single pass is awkward, since you don't know a character's final count until you've seen the whole string.

Why one pass isn't naturally enough

If you scan left to right and keep a running "champion," you can't compare a new character's count so far against the champion's final count — you don't know the final count yet. Better to separate the two jobs: first get the complete frequency of every character, then figure out ordering separately.

Splitting into two clean passes

  1. Pass one — count everything. Walk the string once and build a map from character to total count. After this, no character's count can change.
  2. Pass two — find the first to hit the max. Walk the string again in its original order. For each character, look up its final count. Whenever a character's count is strictly greater than your current best, update your answer.

Why strict greater-than solves the tie-break for free

Because pass two scans in original order, and you only replace your best on a strictly greater count, the first character to reach the max frequency keeps its spot. A later character with the same max count only ties — it never beats it, so it can't overwrite the earlier one. "Earliest wins ties" falls out automatically, no extra logic required.

Why this is efficient and not a compromise

Each pass touches the string once, so two passes of size n is still O(n), not something worse. The only extra memory is the frequency map — at most one entry per distinct character. Compare that to rescanning the whole string for every character, which costs O(n²) in the worst case. Splitting "count" from "decide" is a useful pattern whenever a decision depends on both an aggregate (total count) and a position (who came first): compute the aggregate fully, then make the position-aware decision in a second pass.

main.py
Console
Press Run to execute your code, or Submit to test and complete this problem.