1. 程式人生 > >LeetCode解題 387. 字串中的第一個唯一字元

LeetCode解題 387. 字串中的第一個唯一字元

文章已同步更新到本人個人部落格跳轉連結
題目描述:
給定一個字串,找到它的第一個不重複的字元,並返回它的索引。如果不存在,則返回 -1。

案例:

s = "leetcode"
返回 0.

s = "loveleetcode",
返回 2.

注意事項:您可以假定該字串只包含小寫字母。

這道題很容易做出來,但是想要提交通過,就必須降低時間複雜度,否則會超時。

class Solution:
	"""
    :type s: str
    :rtype: int
    """
    def firstUniqChar(s):
        for elem in s:
            if s.count(elem) == 1:
                return s.index(elem)
        
        return -1

這是我的第一版本,看著很簡潔,對字串進行遍歷,每一個都count一下,等於1,返回索引,否則返回-1,自己電腦上執行,沒問題,線上提交答案,超時。時間複雜度O(n)。需要遍歷、統計大量的重複字元,太浪費時間。

接下來想法去優化,避免去統計重複的字串,就先要去重,我選擇了使用內建模組collections中的Counter方法,下面是第二版本:

class Solution:
    def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """
        from collections import Counter
        s_dict = Counter(s)
        num = len(s)
        count = 0
        for elem in s_dict:
            if s_dict[elem] == 1:
                elem_index = s.index(elem)
                if elem_index <= num:
                	   # 保持num 始終是不重複字元的最小索引
                    num = elem_index
                    # num是第一個字元的時候,就不需要繼續了,
                    if num == 0:
                        break
            else:
                # count 統計遍歷次數,用來判斷是不是沒有不重複的字元
                count += 1
        if count == len(s_dict):
            return -1
        else:
            return num

使用Counter計數,這樣就會返回一個有鍵值對組成的Counter物件,鍵是字串中的元素,值是該元素出現的次數,由於它是無序的,還不能滿足獲取索引的要求,需要一個指標,讓他始終指向索引最小的不重複元素,num初始值是字串的長度,只要有索引比num小的不重複字元,就把較小的索引賦值給num,考慮到會有沒有不重複的字元這種情況,不能直接返回num,需要判斷一下。測試通過後,我有迫不及待的提交了,果然,是用Counter後大幅度的降低了遍歷次數,通過了,超過了87%的提交答案。
在這裡插入圖片描述

回頭看看自己的程式碼,添加註釋,做記錄,突然感覺count這裡,還可以優化一下;每遍歷一次,做一個加操作,如果字串特別長、不重複字元特別多,假設字串長度為n,不重複字串數量為m,在使用Counter返回的物件裡,索引最小的字元在最後一位的話,就要做m次加操作,怎麼在提高一下呢?腦子裡有幾個思路,選了一個試試,踩了幾次‘雷’後,第三版本誕生了,

class Solution:
    def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """
        from collections import Counter
        if s and s.count(s[0])==1:
            return 0
        length = len(s) + 1
        s_dict = Counter(s)
        num = length
        for elem in s_dict:
            if s_dict[elem] == 1:
                elem_index = s.index(elem)
                if elem_index <= num:
                    num = elem_index
                    if num == 0:
                        break
        if num < length:
            return num
        else:
            return -1

這裡先對字串s進行判斷,不為空、0位索引的字串為不重複字串這種極端情況,直接返回結果,length比s的長度大1,最後,只要num小於length,num就是正確結果,否則,就沒有不重複字元,直接返回-1,提交結果不出所料,又提高了2%。
在這裡插入圖片描述
這已經是我目前能做出來的最好結果了,以後有更優解,再來更新!