1. 程式人生 > 實用技巧 >劍指offer_50_第一個只出現一次的字元

劍指offer_50_第一個只出現一次的字元

第一個只出現一次的字元

題目連結:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/

題目內容:

在字串 s 中找出第一個只出現一次的字元。如果沒有,返回一個單空格。 s 只包含小寫字母。

示例:

s = "abaccdeff"
返回 "b"

s = "" 
返回 " "

限制

0 <= s 的長度 <= 50000

題目解析

題目解析內容來自於題解中 Krahets

這題題意簡單明瞭。立刻就能想到雜湊表來統計,遍歷。對應 python 中的字典

但是在如何使用字典這件事中仍然大有可為。

方法一:雜湊表
  1. 遍歷字元 s,使用字典統計"各字元數量是否 > 1"。
  2. 再遍歷字串 s,在字典中找到首個"數量為 1 的字元",並返回

演算法流程

  1. 初始化:生成一個空字典。記為 dic

  2. 字元統計:遍歷字串 s中每一個字元 c

    1. dict不包含 鍵(key) c:則向 dic 中新增鍵值對(c, true),代表字元 c 的數量為 1;
    2. dict包含 鍵(key) c:則修改 dicc 的值為 false,代表字元 c 的數量 > 1;
  3. 查詢數量為1的字元

    :遍歷字串 s 中每個字元 c; 若dic中鍵c對應的值為True,則返回c

  4. 返回 " ", 代表字串無數量為 1 的字元

複雜度分析:
  • 時間複雜度O(N): N 為字串 s的長度;序遍歷 s兩輪,使用 O(N); 字典查詢的時間複雜度為 O(1)
  • 空間複雜度O(N): 字典需儲存 N 個字元的鍵值對,使用 O(N) 大小的額外空間
程式碼

Python 程式碼中 not c in dic 整體為一個布林值,c in dic 為判斷字典中是否含有鍵 c

class Solution:
    def firstUniqChar(self, s: str) -> str:
        dic = {}
        for c in s:
            dic[c] = not c in dic
        for c in s:
            if dic[c]: return c
        return " "
方法二:有序雜湊表

在雜湊表的基礎上,有序雜湊表中的鍵值對是 按照插入順序排序 的。基於此,可通過遍歷有序雜湊表,實現搜尋首個 “數量為 1 的字元”。

雜湊表是 去重 的,即雜湊表中鍵值對數量 \leq≤ 字串 s 的長度。因此,相比於方法一,方法二減少了第二輪遍歷的迴圈次數。當字串很長(重複字元很多)時,方法二則效率更高。

複雜度分析:

時間和空間複雜度均與 “方法一” 相同,而具體分析時間複雜度:

  • 方法一 O(2N) : N 為字串 s 的長度;需遍歷 s 兩輪;
  • 方法二 O(N):遍歷 s 一輪,遍歷 dic 一輪。
程式碼

python3.6 之後,預設字典就是有序的。詳情可見為什麼Python 3.6以後字典有序並且效率更高?

class Solution:
    def firstUniqChar(self, s: str) -> str:
        dic = {}
        for c in s:
            dic[c] = not c in dic
        for k, v in dic.items():
            if v: return k
        return " "