387. First Unique Character in a String - Explanation

Problem Link

Description

You are given a string s, find the first non-repeating character in it and return its index. If it does not exist, return -1.

Example 1:

Input: s = "neetcodeislove"

Output: 0

Explanation: The character 'n' at index 0 is the first character that does not occur at any other index.

Example 2:

Input: s = "neetcodeneet"

Output: 4

Example 3:

Input: s = "baab"

Output: -1

Constraints:

  • 1 <= s.length <= 1,00,000
  • s consists of only lowercase English letters.


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Hash Maps - Used to count character frequencies in O(1) time per operation
  • String Iteration - Traversing strings and accessing characters by index

1. Brute Force

Intuition

For each character in the string, we check if it appears anywhere else. If a character has no duplicate, it is unique. The first such character we find (going left to right) is our answer.

Algorithm

  1. Iterate through each index i in the string.
  2. For each character at i, compare it with every other character at index j.
  3. If a match is found (where i != j), mark it as non-unique and break.
  4. If no match is found after checking all positions, return i.
  5. If no unique character exists, return -1.
class Solution:
    def firstUniqChar(self, s: str) -> int:
        for i in range(len(s)):
            flag = True
            for j in range(len(s)):
                if i == j:
                    continue
                if s[i] == s[j]:
                    flag = False
                    break
            if flag:
                return i
        return -1

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(1)O(1)

2. Hash Map

Intuition

Instead of checking every pair of characters, we can count the frequency of each character in a single pass. Then, in a second pass, we find the first character whose count is exactly 1. This trades space for time.

Algorithm

  1. Create a hash map to store the count of each character.
  2. First pass: iterate through the string and increment the count for each character.
  3. Second pass: iterate through the string again and return the index of the first character with count equal to 1.
  4. If no unique character is found, return -1.
class Solution:
    def firstUniqChar(self, s: str) -> int:
        count = defaultdict(int)
        for c in s:
            count[c] += 1

        for i, c in enumerate(s):
            if count[c] == 1:
                return i
        return -1

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) since we have at most 2626 different characters.

3. Hash Map (Optimal)

Intuition

We can optimize the second pass by iterating over the hash map instead of the string. For each character, we store its first occurrence index. If the character appears again, we mark it as non-unique by setting its index to n (string length). Finally, we find the minimum index among all unique characters.

Algorithm

  1. Create a hash map where each character maps to its first occurrence index.
  2. Iterate through the string:
    • If the character is not in the map, store its index.
    • If it already exists, mark it as non-unique by setting the value to n.
  3. Find the minimum value in the hash map.
  4. Return the minimum index if it's less than n, otherwise return -1.
class Solution:
    def firstUniqChar(self, s: str) -> int:
        n = len(s)
        count = defaultdict(int)
        for i, c in enumerate(s):
            if c not in count:
                count[c] = i
            else:
                count[c] = n

        res = n
        for c in count:
            res = min(res, count[c])

        return -1 if res == n else res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) since we have at most 2626 different characters.

4. Iteration

Intuition

Since the string contains only lowercase letters, we can iterate through all 26 characters and find the first occurrence of each. If a character's first and last occurrence are the same index, it appears exactly once. We track the minimum such index across all characters.

Algorithm

  1. Initialize res to the string length n.
  2. For each character from 'a' to 'z':
    • Find its first occurrence index using indexOf (or equivalent).
    • Find its last occurrence index using lastIndexOf.
    • If both indices are equal and the character exists, update res with the minimum.
  3. Return res if it's less than n, otherwise return -1.
class Solution:
    def firstUniqChar(self, s: str) -> int:
        res = n = len(s)
        for ch in range(ord('a'), ord('z') + 1):
            index = s.find(chr(ch))
            if index != -1 and s.rfind(chr(ch)) == index:
                res = min(res, index)

        return -1 if res == n else res

Time & Space Complexity

  • Time complexity: O(26n)O(26 * n) since we have at most 2626 different characters.
  • Space complexity: O(1)O(1)

Common Pitfalls

Returning the Character Instead of the Index

The problem asks for the index of the first unique character, not the character itself. A common mistake is returning the character or returning a 1-based index instead of a 0-based index. Always double-check what the problem is asking for and ensure your return type matches.

Iterating Over the Hash Map Instead of the String

When using a hash map to count frequencies, iterating over the map to find the first unique character loses the original order. Hash maps in most languages do not preserve insertion order. You must iterate over the original string in a second pass to find the first character with count equal to 1.