Most Frequent Character in a String | Geeks For Geeks Classic.

Prashant GuptaPrashant Gupta
3 min read

When I first saw the problem “Find the most frequent character in a string” on GeeksforGeeks, my initial thought was - “Oh, this looks simple, I can just count and pick the max.” But as I started coding, I realized there’s a little twist - if two characters have the same frequency, then I need to return the lexicographically smaller character.

Let’s solve this together.

Step 1: The Naive Approach - Using Counter

Like most of us, my first instinct was to use Python’s built-in collections.Counter.

from collections import Counter

def getMaxOccurringChar(s):
    freq = Counter(s)
    return max(freq, key=freq.get)

print(getMaxOccurringChar("output"))

At first glance, this looks fine. It gives us the most frequent character.

But there’s a catch, in "output", both 't' and 'u' appear twice.
max() will just pick whichever it sees first, not the lexicographically smaller one.
So the answer should be 't', but my function could fail.

Step 2: Adding Lexicographic Ordering

To fix this, I thought - “Why not sort the characters alphabetically before checking frequency? That way, in case of a tie, the lexicographically smaller one comes first.”

Here’s the code:

def getMaxOccurringChar(s):
    freq = {}
    # Step 1: Frequency map
    for ch in s:
        if ch not in freq:
            freq[ch] = 1
        else:
            freq[ch] += 1

    # Step 2: Sort by character (lexicographically)
    freq = dict(sorted(freq.items()))
    maxi = 0
    res = None

    # Step 3: Find max frequency character
    for key, value in freq.items():
        if maxi < value:
            maxi = value
            res = key

    return res

print(getMaxOccurringChar("test"))    # t
print(getMaxOccurringChar("output"))  # t

Now it works

Step 3: Optimized Approach Without Sorting

Sorting gives the right answer, but adds unnecessary O(K log K) complexity (K = distinct characters).

So I improved it further: while scanning, if two characters have the same frequency, just compare them directly.

def getMaxOccurringChar(s):
    freq = {}
    # Step 1: Build frequency map
    for ch in s:
        freq[ch] = freq.get(ch, 0) + 1

    # Step 2: Track max freq + lexicographically smallest
    maxi = 0
    res = None

    for key in freq:
        if freq[key] > maxi or (freq[key] == maxi and key < res):
            maxi = freq[key]
            res = key

    return res

print(getMaxOccurringChar("test"))    # t
print(getMaxOccurringChar("output"))  # t

This directly enforces the condition:

  • Higher frequency → update.

  • Same frequency → check lexicographically smaller.

Time & Space Complexity

Approach 1: Using Counter only

  • Time Complexity: O(N) for counter + O(K) for scan.

  • Fails for lexicographic condition without extra handling.

Approach 2: Sorting + Dictionary

  • Time Complexity: O(N + K log K)

  • Space Complexity: O(K)

Approach 3: Optimized Dictionary (Best)

  • Time Complexity: O(N + K) (practically O(N))

  • Space Complexity: O(K)

Final Thoughts

What I really liked about this problem was how a “simple” task of finding the most frequent character actually pushed me to think about edge cases like lexicographic ordering.

  • First, I rushed with “Counter”.

  • Then I realized I needed sorting.

  • Finally, I optimized it with direct comparisons.

Lesson learned: Don’t stop at the first working solution. Always refine and check edge cases like ties, because that’s where your logic is truly tested.

0
Subscribe to my newsletter

Read articles from Prashant Gupta directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prashant Gupta
Prashant Gupta