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%。
這已經是我目前能做出來的最好結果了,以後有更優解,再來更新!