JZ50. 第一个只出现一次的字符

20 阅读1分钟

leetcode.cn/problems/di…

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

示例 1:

输入:s = "abaccdeff" 输出:'b' 示例 2:

输入:s = "" 输出:' '  

限制:

0 <= s 的长度 <= 50000

本题考察 哈希表 的使用,本文介绍 哈希表 和 有序哈希表 两种解法。其中,在字符串长度较大、重复字符很多时,“有序哈希表” 解法理论上效率更高。

方法一:哈希表

遍历字符串 s ,使用哈希表统计 “各字符数量是否 >1 ”。

再遍历字符串 s ,在哈希表中找到首个 “数量为 1 的字符”,并返回。

image.png

算法流程:

image.png

复杂度分析:

时间复杂度 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;
    }
}