查找第一個不重復的字符問題
最近去面了一次試,最后面到一次算法題。說實話,以前去面試很少面到算法題,可能和面試的職位有關的。
相當常見的題目,說是找出一堆數字中第一個出現的不重復的數字。當時沒理解清題目,想成了是只有一個不重復的數字。后來面試官跟我說明清楚了題目之后,瞬間沒了啥思路,也沒答好。后來回去路上一想,感覺也相當簡單。
這個題目原題是 “找出一個字符串(只包含英文,不考慮中文等字符問題)中第一個不重復的數字”。
如果不做限制,很容易想到的方法是:從頭開始遍歷一下字符串,針對每個字符再從開開始查找是否有重復的,找到第一個整個字符串中沒有重復的字符。當然時間復雜度為 O(n2),肯定不是最優解。
比較普遍的方法是犧牲一定的空間復雜度,用一個數組暫存一下字符串中每個字符出現的次數,再重新從頭開始遍歷字符串,找到次數為 1 的字符返回。
代碼如下:
func searchFirstNotDuplicatedChar(str string) string {
cnts := make([]int, 256)
for _, s := range str {
cnts[s]++
}
for _, s := range str {
if cnts[s] == 1 {
return string(s)
}
}
return ""
}
復雜度就是遍歷了兩次字符串,時間復雜度為 O(n)。已經相當可以了。
當然面試官給我出的原題是一堆數字,不是字符串(這和我面試時提到的以往的工作有關,處理批量數據)。因為我們知道英文字符處於 ASCII 碼表中很容易做對應。而數字類數據的話因為不知道范圍,很難用一個數組來做存儲對應,所以這個我們可以考慮用一個 Map。我們知道 Hash 方法是很快速的,所以幾乎不存在什么性能問題。
這個為了簡便,只考慮了整形 int 類型的數據。
func findFirstNotDuplicatedInt(nums []int) int {
cnts := make(map[int]int)
for _, num := range nums {
cnts[num]++
}
for _, num := range nums {
if cnts[num] == 1 {
return num
}
}
return -1
}
就稍微改了一下,依然是 O(n)。差不多是這個。據說還有使用位運算的算法可以做到,暫時沒研究,感覺這樣已經很不錯了。
對於算法題,面試和自己平常在電腦上做,感覺真是不一樣的。面試中包含各種不確定的因素,而且人也容易產生緊張感,往往有些平常很容易想到的東西面試中就犯迷糊了。復雜的算法由於平時幾乎不太用到,也是看過就很容易忘。所以我覺得培養一種對於算法的直覺相當重要。