AlgoMaster Logo

First Unique Character in a String

easyFrequency7 min readUpdated June 23, 2026

Understanding the Problem

We need to find the first character in the string that appears exactly once. "First" means the leftmost position, and "unique" means its count in the entire string is exactly one. If every character repeats, we return -1.

The challenge is the ordering. Deciding whether a character is unique requires the frequency of every character, which is global information about the whole string. But picking the answer requires the leftmost qualifying position, which is positional information. The two requirements pull in different directions, and that tension shapes the approaches below.

Key Constraints:

  • 1 <= s.length <= 10^5 → With n up to 100,000, O(n^2) is borderline. O(n log n) and O(n) are safe. We should aim for O(n).
  • s consists of only lowercase English letters → Only 26 possible characters. A fixed-size array of length 26 is enough for counting, giving us O(1) space.

Approach 1: Brute Force

Intuition

For each character in the string, check whether it appears anywhere else. The first character with no duplicate is the answer.

This mirrors scanning a word by hand: take the first letter, look through the rest of the word for a match, and if none exists, that letter is the answer. Otherwise move to the next letter and repeat. Because we examine positions left to right, the first letter we find without a duplicate is automatically the leftmost one.

Algorithm

  1. Iterate through the string with index i from 0 to n-1.
  2. For each character at index i, iterate through the entire string with index j.
  3. If j != i and s[j] == s[i], the character is not unique. Break and move to the next i.
  4. If the inner loop completes without finding a duplicate, return i.
  5. If no unique character is found after checking all positions, return -1.

Example Walkthrough

1i=0: check if 'l' appears elsewhere in the string
0
i
l
1
o
2
v
3
e
4
l
5
e
6
e
7
t
8
c
9
o
10
d
11
e
1/6

Code

The brute force rescans the entire string for every character, recomputing duplicate information it has already seen. Counting each character's frequency once upfront turns every uniqueness check into an O(1) lookup.

Approach 2: Two-Pass Frequency Count

Intuition

Instead of repeatedly scanning for duplicates, count the frequency of every character in one pass, then make a second pass to find the first character with a count of exactly 1.

This splits the problem into two independent tasks: figure out which characters are unique, then find the leftmost one. The first task needs global information, so it scans the whole string. The second task needs positional information, so it scans left to right. Running them as two sequential passes keeps each one simple.

Since the string contains only lowercase English letters, a fixed-size array of 26 integers is enough to hold the counts. Array indexing avoids hash lookups, and the space stays constant regardless of input size.

Algorithm

  1. Create a frequency array of size 26 initialized to zeros.
  2. First pass: iterate through the string and count the frequency of each character.
  3. Second pass: iterate through the string again. For each character, check its frequency in the array. Return the index of the first character with frequency 1.
  4. If no character has frequency 1, return -1.

Example Walkthrough

s
1Pass 1: count all character frequencies
0
l
1
o
2
v
3
e
4
l
5
e
6
e
7
t
8
c
9
o
10
d
11
e
counting
count
1Building frequency map from string...
1/6

Code

This is optimal for a fixed string given all at once. A common follow-up changes the setting: characters arrive one at a time as a stream, and after each arrival you must report the first unique character seen so far. The next approach handles that case and also solves the original problem in a single pass.

Approach 3: Streaming with a Queue

Intuition

The two-pass approach assumes the entire string is available before we start. A harder variant feeds characters one at a time and asks for the current first unique character after every arrival. We cannot make a second pass, because future characters have not arrived yet.

The fix is to keep a queue of candidate indices in arrival order, alongside the frequency counts. Each index enters the queue once, when its character first arrives. The front of the queue holds the oldest index that is still a candidate for "first unique." A candidate stops being valid the moment its character's count rises above 1, so before reading the answer we discard any front entries whose character now repeats. Whatever remains at the front is the first unique character. If the queue empties, no unique character exists.

This also solves the original fixed-string problem in a single pass: feed the characters in order, and the queue front after the last character is the final answer.

Algorithm

  1. Create a frequency array of size 26 and an empty queue of indices.
  2. Walk the string once. For each index i with character c: increment count[c], and if this is the first time c is seen (count becomes 1), push i onto the queue.
  3. After incrementing, drop indices from the front of the queue while the character at the front index has a count greater than 1. Those characters are no longer unique.
  4. After processing the whole string, the front of the queue is the index of the first unique character. Return it, or -1 if the queue is empty.

Example Walkthrough

s
1i=0 'l': count l=1, push index 0. Front candidate is 'l' at 0.
0
front
l
1
o
2
v
3
e
4
l
5
e
6
e
7
t
8
c
9
o
10
d
11
e
queue
1Push 0. queue = [0]
0
0
1/13

Code