const solve = (nums) => { let left = 0, right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target) return [left, right]; }}
Problem Walkthrough

First Unique Character LeetCode: Frequency Count Explained

LeetCode 387 is the simplest frequency count plus scan problem — count all characters first, then find the first one with count 1.

5 min read|

Count first, scan second — the two-pass frequency pattern

The simplest frequency count problem that teaches a pattern behind dozens of string problems

First Unique Character: The Two-Pass Frequency Pattern

First Unique Character in a String (LeetCode #387) is one of the cleanest introductions to the frequency count pattern you will find on LeetCode. The first unique character leetcode problem asks a straightforward question: given a string, find the index of the first character that appears exactly once. If no such character exists, return -1.

What makes this problem valuable is not its difficulty — it is rated Easy for good reason. The value is in the pattern it teaches. The two-pass frequency approach — count everything first, then scan for the answer — is the same technique behind Valid Anagram (#242), Ransom Note (#383), and Group Anagrams (#49). Master it here where the logic is simple, and you will recognize it instantly in harder problems.

By the end of this walkthrough, you will understand exactly why two passes are cleaner than one, how frequency counting works with a hash map, and why this pattern recurs across dozens of string and array problems. This is the foundation problem for frequency-based thinking.

Understanding the Problem

The problem gives you a string s consisting of lowercase English letters. You need to find the first non repeating character in the string and return its index. If every character repeats, return -1. The key word is "first" — you are not just checking whether a unique character exists, you need to find the earliest one.

For example, in the string "leetcode", the character "l" appears once and sits at index 0. Even though "t", "c", "o", "d" also appear once, "l" comes first. That is why the answer is 0. In "loveleetcode", the character "v" at index 2 is the first non repeating character. In "aabb", every character repeats, so the answer is -1.

The constraint that the string contains only lowercase English letters is important. It means there are at most 26 distinct characters, which keeps the space complexity constant regardless of input length. This is a detail interviewers expect you to mention when analyzing your solution.

ℹ️

Interview Insight

First Unique Character (#387) is Amazon's most-asked Easy string problem — it tests the frequency count pattern that underlies Valid Anagram, Ransom Note, and Group Anagrams.

The Two-Pass Approach

The leetcode 387 solution uses a clean two-pass strategy. In the first pass, iterate through the entire string and count how many times each character appears. Store these counts in a hash map (or a fixed-size array of 26 slots for lowercase letters). After this pass, you know the exact frequency of every character.

In the second pass, iterate through the string again from left to right. For each character, look up its count in the hash map. The first character you find with a count of exactly 1 is your answer — return its index immediately. If you finish the entire second pass without finding any character with count 1, return -1.

Why two passes instead of one? You could try tracking insertion order and counts simultaneously, but it adds unnecessary complexity. The two-pass approach separates concerns cleanly: pass one gathers data, pass two answers the question. The hash map first unique technique keeps both passes at O(n), and the total work is still O(n) with O(1) space since there are at most 26 distinct lowercase characters.

Implementation

The first unique char explained in code is remarkably concise. Create a hash map or dictionary. Loop through the string once, incrementing the count for each character. Then loop through the string a second time, checking each character's count. Return the index of the first character whose count equals 1.

In Python, you can use collections.Counter for pass one, then enumerate the string for pass two. In JavaScript, a plain object or Map works for the counter. In Java, an int array of size 26 is the most efficient approach since you can map each character to an index with c - 'a'. Regardless of language, the logic is identical.

The time complexity is O(n) for each pass, giving O(n) overall. The space complexity is O(1) because the frequency map holds at most 26 entries — a constant that does not grow with the input. This is the optimal solution and exactly what interviewers expect.

  • Pass 1: Build frequency map — iterate string, count each character
  • Pass 2: Scan string left to right — return first index where count == 1
  • If no character has count 1 after full scan, return -1
  • Time complexity: O(n) — two linear passes
  • Space complexity: O(1) — at most 26 character counts

Visual Walkthrough

Let us trace through three examples to cement the frequency count unique pattern. For the input "leetcode", pass one builds the frequency map: l=1, e=3, t=1, c=1, o=1, d=1. Pass two scans from left: index 0 is "l" with count 1 — that is our answer. Return 0.

For "loveleetcode", pass one builds: l=2, o=2, v=1, e=4, t=1, c=1, d=1. Pass two scans: index 0 "l" has count 2 (skip), index 1 "o" has count 2 (skip), index 2 "v" has count 1 — return 2. Notice the second pass preserves the original order of the string, which is how we find the first unique character.

For "aabb", the frequency map is: a=2, b=2. Pass two checks every character and finds none with count 1. Return -1. The beauty of this approach is that it handles all three outcomes — early unique, late unique, and no unique — with the exact same code path.

  1. 1"leetcode" -> counts: {l:1, e:3, t:1, c:1, o:1, d:1} -> scan: l at index 0 has count 1 -> return 0
  2. 2"loveleetcode" -> counts: {l:2, o:2, v:1, e:4, t:1, c:1, d:1} -> scan: v at index 2 has count 1 -> return 2
  3. 3"aabb" -> counts: {a:2, b:2} -> scan: no character with count 1 -> return -1
⚠️

Common Mistake

Don't return the first unique character — return its INDEX. This is a common mistake: the answer for 'loveleetcode' is 2 (index of 'v'), not 'v' itself.

Edge Cases

A single character string like "a" has one character with count 1, so you return 0. A string where every character is unique, like "abcdef", also returns 0 because the first character is already unique. Both cases are handled naturally by the two-pass approach without any special logic.

A string where no character is unique, like "aabbcc", results in -1. A string where the only unique character is the very last one, like "aabbc", returns 4. The second pass will scan past all the repeated characters and find "c" at the end. This is why scanning left to right in the second pass is essential — it guarantees you find the first unique character by position.

The problem guarantees the string contains only lowercase English letters and has at least one character. You do not need to handle empty strings, uppercase letters, or special characters. This keeps the solution clean and lets you focus on the pattern rather than input validation.

  • All unique characters (e.g., "abc"): return 0 — first character is already unique
  • No unique characters (e.g., "aabb"): return -1
  • Single character (e.g., "a"): return 0
  • Unique character at the end (e.g., "aabbc"): return the last index
  • All same character (e.g., "aaaa"): return -1

What First Unique Character Teaches You

First Unique Character teaches the two-pass frequency pattern that shows up repeatedly across LeetCode. The first unique string approach — count first, scan second — is the same strategy used in Ransom Note (#383), where you count available characters and then check if you have enough. It is the same idea behind Valid Anagram (#242), where you count both strings and compare frequencies.

The broader lesson is that frequency counting with a hash map is one of the most versatile techniques in algorithm interviews. Any time a problem asks about character counts, duplicates, or uniqueness, your first instinct should be to build a frequency map. The pattern scales from Easy problems like this one to Medium problems like Group Anagrams (#49) and hard problems like Minimum Window Substring (#76).

If you found this first unique character leetcode walkthrough helpful, YeetCode flashcards can help you drill the frequency count pattern and other essential algorithm patterns through spaced repetition. The goal is to internalize these patterns so deeply that you recognize them within seconds during an interview.

💡

Pro Tip

Two passes is the clean approach: count everything first, then scan for the first count==1. Don't try to track ordering in the hash map — the second pass handles ordering naturally.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now