LeetCode 387: First Unique Character in a String (Frequency Count + First Pass Index Scan)
LeetCode 387StringHash TableCountingToday we solve LeetCode 387 - First Unique Character in a String.
Source: https://leetcode.com/problems/first-unique-character-in-a-string/
English
Problem Summary
Given a lowercase string s, return the index of the first non-repeating character. If every character appears more than once, return -1.
Key Insight
Whether a character is unique depends on its total frequency in the whole string. So we first count each letter, then scan again from left to right to find the first index whose count is exactly 1.
Brute Force and Limitations
Brute force checks each index by scanning the full string again to test uniqueness, which leads to O(n^2) time and is unnecessary.
Optimal Algorithm Steps
1) Build a frequency array of size 26.
2) First pass: count every character.
3) Second pass: return the first index with frequency 1.
4) If none exists, return -1.
Complexity Analysis
Time: O(n).
Space: O(1) (fixed alphabet size).
Common Pitfalls
- Trying to decide uniqueness in one pass without full counts.
- Returning the smallest unique character value instead of first unique index.
- Forgetting to return -1 when all characters repeat.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public int firstUniqChar(String s) {
int[] freq = new int[26];
for (int i = 0; i < s.length(); i++) {
freq[s.charAt(i) - 'a']++;
}
for (int i = 0; i < s.length(); i++) {
if (freq[s.charAt(i) - 'a'] == 1) {
return i;
}
}
return -1;
}
}func firstUniqChar(s string) int {
freq := make([]int, 26)
for i := 0; i < len(s); i++ {
freq[s[i]-'a']++
}
for i := 0; i < len(s); i++ {
if freq[s[i]-'a'] == 1 {
return i
}
}
return -1
}class Solution {
public:
int firstUniqChar(string s) {
int freq[26] = {0};
for (char c : s) {
freq[c - 'a']++;
}
for (int i = 0; i < (int)s.size(); i++) {
if (freq[s[i] - 'a'] == 1) return i;
}
return -1;
}
};class Solution:
def firstUniqChar(self, s: str) -> int:
freq = [0] * 26
for ch in s:
freq[ord(ch) - ord('a')] += 1
for i, ch in enumerate(s):
if freq[ord(ch) - ord('a')] == 1:
return i
return -1var firstUniqChar = function(s) {
const freq = new Array(26).fill(0);
for (let i = 0; i < s.length; i++) {
freq[s.charCodeAt(i) - 97]++;
}
for (let i = 0; i < s.length; i++) {
if (freq[s.charCodeAt(i) - 97] === 1) {
return i;
}
}
return -1;
};中文
题目概述
给定一个只包含小写字母的字符串 s,返回第一个不重复字符的下标;如果不存在,返回 -1。
核心思路
某个字符是否唯一,取决于它在全串中的总出现次数。最稳妥的方法是两遍扫描:第一遍统计频次,第二遍按原顺序找第一个频次为 1 的位置。
暴力解法与不足
对每个位置都再扫一遍字符串来判断是否重复,会产生 O(n^2) 时间复杂度,输入长时会明显变慢。
最优算法步骤
1)准备长度为 26 的计数数组。
2)第一遍遍历,累计每个字母出现次数。
3)第二遍遍历,遇到频次为 1 的字符立刻返回其下标。
4)若遍历结束仍未命中,返回 -1。
复杂度分析
时间复杂度:O(n)。
空间复杂度:O(1)(字母表大小固定)。
常见陷阱
- 想一遍遍历直接判唯一,导致逻辑漏洞。
- 返回“字典序最小唯一字符”而不是“最先出现的唯一字符下标”。
- 没有处理全重复场景,漏掉 -1 返回。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public int firstUniqChar(String s) {
int[] freq = new int[26];
for (int i = 0; i < s.length(); i++) {
freq[s.charAt(i) - 'a']++;
}
for (int i = 0; i < s.length(); i++) {
if (freq[s.charAt(i) - 'a'] == 1) {
return i;
}
}
return -1;
}
}func firstUniqChar(s string) int {
freq := make([]int, 26)
for i := 0; i < len(s); i++ {
freq[s[i]-'a']++
}
for i := 0; i < len(s); i++ {
if freq[s[i]-'a'] == 1 {
return i
}
}
return -1
}class Solution {
public:
int firstUniqChar(string s) {
int freq[26] = {0};
for (char c : s) {
freq[c - 'a']++;
}
for (int i = 0; i < (int)s.size(); i++) {
if (freq[s[i] - 'a'] == 1) return i;
}
return -1;
}
};class Solution:
def firstUniqChar(self, s: str) -> int:
freq = [0] * 26
for ch in s:
freq[ord(ch) - ord('a')] += 1
for i, ch in enumerate(s):
if freq[ord(ch) - ord('a')] == 1:
return i
return -1var firstUniqChar = function(s) {
const freq = new Array(26).fill(0);
for (let i = 0; i < s.length; i++) {
freq[s.charCodeAt(i) - 97]++;
}
for (let i = 0; i < s.length; i++) {
if (freq[s.charCodeAt(i) - 97] === 1) {
return i;
}
}
return -1;
};
Comments