- 雜湊表
- 任務
- 242.有效的字母異位詞
- 思路
- 349. 兩個陣列的交集
- 思路
- 202. 快樂數
- 思路
- 1.兩數之和
- 思路
- 242.有效的字母異位詞
- 心得體會
雜湊表
什麼時候用雜湊表呢?快速判斷元素是否在集合中,或者元素去重(集合),或者統計重複元素的數量(字典)。
任務
242.有效的字母異位詞
給定兩個字串 s 和 t ,編寫一個函式來判斷 t 是否是 s 的字母異位詞。
注意:若 s 和 t 中每個字元出現的次數都相同,則稱 s 和 t 互為字母異位詞。s 和 t 僅包含小寫字母。
思路
使用兩個map,key為字元,value為出現次數,比較兩個map每個key對應的value是否相同。
- 長度不同一定不同,直接返回False
- 在1不成立的情況下,即長度如果相同時,map2中沒有某個map1中的key,返回False
- 在2不成立的情況下,即兩者的所有key都相同時,對應的value有不相等的情況,返回False
- 否則返回True
經過學習,知道python中可以直接判斷兩個字典相等,於是不需要自己寫上面的邏輯
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
dic1 = {}
for c in s:
if c not in dic1:
dic1[c] = 1
else:
dic1[c]+=1
dic2 = {}
for c in t:
if not dic2.__contains__(c):
dic2[c] = 1
else:
dic2[c]+=1
# if len(dic1) != len(dic2):
# return False
# for c in dic1:
# if c not in dic2 or dic1[c] != dic2[c]:
# return False
# return True
return dic1 == dic2
另外,可以使用Python collections模組之defaultdict()來避免異常和約束資料型別。
此外以上都是使用了雜湊字典的方法,實際此題還可以使用陣列作為桶,用下標去作為索引對映26個字母(當前字元-'a'為下標),然後用其值用來表示出現的次數。然後比較兩個陣列是否相同。更簡單地,還可以只用一個陣列,統計第一個字串的時候統計次數用加,第二個的時候用減,然後遍歷陣列看是否等於0。
349. 兩個陣列的交集
給定兩個陣列 nums1 和 nums2 ,返回它們的交集。輸出結果中的每個元素一定是唯一的。我們可以不考慮輸出結果的順序。
思路
將兩個陣列去重,變為兩個集合。然後遍歷數量小的集合,判斷它的每個元素是否在數量大的集合中,如果在,則加入到目標集合(交集)。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
result = []
set1 = set()
for e in nums1:
set1.add(e)
set2 = set()
for e in nums2:
set2.add(e)
lessSet = set1 if len(set1) <= len(set2) else set2
moreSet = set1 if set2 is lessSet else set2
for e in lessSet:
if e in moreSet:
result.append(e)
return result
實際上用python直接提供了求交集的方法,直接求集合的交集。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2))
202. 快樂數
編寫一個演算法來判斷一個數 n 是不是快樂數。
「快樂數」 定義為:
對於一個正整數,每一次將該數替換為它每個位置上的數字的平方和。
然後重複這個過程直到這個數變為 1,也可能是 無限迴圈 但始終變不到 1。
如果這個過程 結果為 1,那麼這個數就是快樂數。
思路
按快樂數定義,單次迴圈的步驟如下:
1.每次得到結果後,判斷是否是1,如果是1,則返回True,即為快樂數
2.如果還沒得到1,判斷結果是否在集合中,如果不在,則將其加入到集合中
3.如果在集合中,證明已經陷入無限迴圈,直接返回False
迴圈的條件為while(1)
如何得到值,這裡是個小重點,即如何分解一個n位數的各位數的值,單次迴圈的步驟如下:
1.我們採用% 的方式得到當前數字的個位數,
2.採用整數floor除//的方式得到將個位數去除,得到前n-1形成的一個數字
迴圈條件為n不為0,即至少為1位數。
class Solution:
def isHappy(self, n: int) -> bool:
compareSet = set()
while 1:
n = self.getSum(n)
if n == 1:
return True
if n not in compareSet:
compareSet.add(n)
else:
return False
def getSum(self,n:int) -> int:
sum = 0
while n:
sum += (n%10) *(n%10)
n //=10
return sum
1.兩數之和
給定一個整數陣列 nums 和一個整數目標值 target,請你在該陣列中找出 和為目標值 target 的那 兩個 整數,並返回它們的陣列下標。
你可以假設每種輸入只會對應一個答案。但是,陣列中同一個元素在答案裡不能重複出現。
你可以按任意順序返回答案。
思路
暴力法很容易想到,就是對每個位置的數,查詢其後符合條件的另一個數。
而字典的方法不是很容易想到,這個思路有點像之前的求最短子陣列那道滑動視窗,暴力的方法是找當前位置的值和後面哪個位置匹配,後面都是未知的,因此每次都要遍歷後面的區間,即使實際上上一蹚已經遍歷過了但是沒有留下任何有用的資訊,因此下次處理時還是要遍歷,最終達到O(n^2)的時間複雜度。而最佳化思路是,確定以當前位置為後面的值,找到它前面哪個值和它匹配,而前面的值又存入到集合/字典這樣的資料結構中(記錄了資訊,讓之前的遍歷有了意義),方便查詢(快速判斷元素在集合中),也就是說,只遍歷了一遍,前面的值是已知的,或者說是更快得到結果的,因此可以降低時間複雜度。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dic = {}
result = []
size = len(nums)
for i in range(0,size):
need = target- nums[i]
if need in dic:
result.append(dic[need])
result.append(i)
else:
dic[nums[i]] = i
return result
心得體會
今天主要的思考如下:
1.雜湊表/字典的使用場景,快速判斷元素在集合中,以及去重和統計等。
2.python中的 == 與 is
3.如何處理一個數每個數位上的數 %求最低位,//去掉最低位剩下的數
4.對一個問題思考時,可以採用先用暴力法思考,然後最佳化的思路也許會更容易想到,如之前學到的209. 長度最小的子陣列使用滑動視窗解決,以及今天學到的兩數之和,都是用這種先暴力然後思考暴力法低效的原因(每一次對後區間的遍歷沒有給下一次提供有用的資訊導致的)從而得到最佳化的方法(遍歷過的節點需要給下一次遍歷提供有意義的資訊)。