在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例 1:
输入:s = "abaccdeff" 输出:'b' 示例 2:
输入:s = "" 输出:' '
限制:
0 <= s 的长度 <= 50000
本题考察 哈希表 的使用,本文介绍 哈希表 和 有序哈希表 两种解法。其中,在字符串长度较大、重复字符很多时,“有序哈希表” 解法理论上效率更高。
方法一:哈希表
遍历字符串 s ,使用哈希表统计 “各字符数量是否 >1 ”。
再遍历字符串 s ,在哈希表中找到首个 “数量为 1 的字符”,并返回。
算法流程:
复杂度分析:
时间复杂度 O(N) : N 为字符串 s 的长度;需遍历 s 两轮,使用 O(N) ;HashMap 查找操作的复杂度为 O(1) ;
空间复杂度 O(1) : 由于题目指出 s 只包含小写字母,因此最多有 26 个不同字符,HashMap 存储需占用 O(26)=O(1) 的额外空间。
代码:
Python 代码中的 not c in dic 整体为一个布尔值; c in dic 为判断字典中是否含有键 c 。
class Solution {
public char firstUniqChar(String s) {
char result = ' ';
char[] chars = s.toCharArray();
HashMap<Character, Boolean> hashMap = new LinkedHashMap<>();
for (int i = 0; i < chars.length; i++) {
hashMap.put(chars[i], !hashMap.containsKey(chars[i]));
}
for (int i = 0; i < chars.length; i++) {
if (hashMap.get(chars[i])) {
result = chars[i];
break;
}
}
return result;
}
}
方法二:有序哈希表
在哈希表的基础上,有序哈希表中的键值对是 按照插入顺序排序 的。基于此,可通过遍历有序哈希表,实现搜索首个 “数量为 1 的字符”。
哈希表是 去重 的,即哈希表中键值对数量 ≤ 字符串 s 的长度。因此,相比于方法一,方法二减少了第二轮遍历的循环次数。当字符串很长(重复字符很多)时,方法二则效率更高。
复杂度分析:
时间和空间复杂度均与 “方法一” 相同,而具体分析:方法一 需遍历 s 两轮;方法二 遍历 s 一轮,遍历 dic 一轮( dic 的长度不大于 26 )。
Java 使用 LinkedHashMap
实现有序哈希表。
代码
class Solution {
public char firstUniqChar(String s) {
char result = ' ';
char[] chars = s.toCharArray();
LinkedHashMap<Character, Boolean> hashMap = new LinkedHashMap<>();
for (int i = 0; i < chars.length; i++) {
hashMap.put(chars[i], !hashMap.containsKey(chars[i]));
}
for (Map.Entry<Character, Boolean> characterIntegerEntry : hashMap.entrySet()) {
if (characterIntegerEntry.getValue()) {
result = characterIntegerEntry.getKey();
break;
}
}
return result;
}
}