Leftmost Repeating Character

Medium

Leftmost Repeating Character

Pattern:

Idea:

Variations :


πŸ’» Code

Single Pass

def leftmostRepeating(s):
    visited = [False] * 256
    ans = -1

    for i in range(len(s) - 1, -1, -1):
        idx = ord(s[i])

        if visited[idx]:
            ans = i
        else:
            visited[idx] = True

    return ans

Time complexity - O(n)

Aux. Space complexity - O(1)


Leftmost Repeating Character

Tags: #Strings #Hashing #FrequencyArray #Arrays #Interview-Pattern #FAANG

Problem Statement

Given a string s, return the index of the leftmost character that repeats. If no character repeats, return -1.

A repeating character is one whose frequency is greater than 1.

Example

InputOutputCharacter
"geeksforgeeks"0'g'
"abccbd"1'b'
"abcd"-1β€”

Key Idea

There are two standard interview approaches:

  1. Double Pass β€” Count frequencies, then find the first repeated character.

  2. Single Pass β€” Traverse from right to left while remembering visited characters.

The single-pass approach is more elegant and uses the observation that the last time we encounter a repeating character while moving backwards is its leftmost occurrence.


Approach 1 β€” Double Pass (Frequency Counting)

Intuition

First determine which characters repeat, then locate the first one.

Algorithm

  1. Count frequency of every character.

  2. Scan the string from left to right.

  3. Return the first index whose frequency is greater than 1.

Python Solution

def leftmostRepeating(s):
    freq = [0] * 256

    for ch in s:
        freq[ord(ch)] += 1

    for i, ch in enumerate(s):
        if freq[ord(ch)] > 1:
            return i

    return -1

Dry Run

s = "abccbd"

Frequency:

CharCount
a1
b2
c2
d1

Second pass:

IndexCharRepeating?
0a❌
1bβœ…

Answer = 1


Approach 2 β€” Single Pass (Right to Left)

Intuition (The WHY)

Traverse the string backwards.

Maintain a visited array.

  • First time seeing a character β†’ mark visited.

  • If already visited β†’ update the answer to the current index.

The last update becomes the leftmost repeating character.

Visual Example

s = "abccbd"

Right β†’ Left
IndexCharVisited?Answer
5dNo-1
4bNo-1
3cNo-1
2cYes2
1bYes1
0aNo1

Final answer = 1

Notice how the answer keeps moving left.


Python Solution

def leftmostRepeating(s):
    visited = [False] * 256
    ans = -1

    for i in range(len(s) - 1, -1, -1):
        idx = ord(s[i])

        if visited[idx]:
            ans = i
        else:
            visited[idx] = True

    return ans

Why Right-to-Left Works

Suppose:

s = "abccbd"

The second 'b' is encountered first:

a b c c b d
        ↑

Later, moving left:

a b c c b d
  ↑

We now discover the leftmost occurrence.

Every repeated character updates the answer exactly once, and the smallest index survives.


Complexity

ApproachTimeAuxiliary Space
Double PassO(n)O(1)
Single PassO(n)O(1)

256 is constant for ASCII, so the auxiliary space is considered O(1).


Comparison

FeatureDouble PassSingle Pass
Traversals21
Data StoredFrequencyVisited
Easier to understandβœ…β€”
More elegantβ€”βœ…

In interviews, mention both; the single-pass version is often considered the optimal implementation.


Common Mistakes

1. Returning the First Duplicate Encountered

For:

"abccbd"

The first duplicate encountered while scanning left-to-right is 'c', but the correct answer is 'b'.

The problem asks for the leftmost repeating, not the earliest repeated event.

2. Using a Set Left-to-Right

This incorrectly returns the second occurrence instead of the leftmost occurrence.

3. Forgetting Character Encoding

For lowercase-only problems, use size 26; for general ASCII strings, use 256.


Pythonic Way

Using Counter:

from collections import Counter

def leftmostRepeating(s):
    freq = Counter(s)

    for i, ch in enumerate(s):
        if freq[ch] > 1:
            return i

    return -1

Readable, but slightly less optimal than the fixed-size array due to hashing overhead.


Key Takeaways / Pattern Recognition

  • Need the leftmost repeated element β†’ Frequency counting is the most intuitive.

  • Need it in one traversal β†’ Scan right to left with a visited array.

  • This is a classic interview example showing how changing traversal direction can eliminate an entire pass.

Local Graph View

Start typing to search
Try: two sum or #Arrays or #Amazon