Day6 雜湊表part1

haohaoscnblogs發表於2024-07-22

目錄
  • 雜湊表
  • 任務
    • 242.有效的字母異位詞
      • 思路
    • 349. 兩個陣列的交集
      • 思路
    • 202. 快樂數
      • 思路
    • 1.兩數之和
      • 思路
  • 心得體會

雜湊表

什麼時候用雜湊表呢?快速判斷元素是否在集合中,或者元素去重(集合),或者統計重複元素的數量(字典)。

任務

242.有效的字母異位詞

給定兩個字串 s 和 t ,編寫一個函式來判斷 t 是否是 s 的字母異位詞。
注意:若 s 和 t 中每個字元出現的次數都相同,則稱 s 和 t 互為字母異位詞。s 和 t 僅包含小寫字母。

思路

使用兩個map,key為字元,value為出現次數,比較兩個map每個key對應的value是否相同。

  1. 長度不同一定不同,直接返回False
  2. 在1不成立的情況下,即長度如果相同時,map2中沒有某個map1中的key,返回False
  3. 在2不成立的情況下,即兩者的所有key都相同時,對應的value有不相等的情況,返回False
  4. 否則返回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. 長度最小的子陣列使用滑動視窗解決,以及今天學到的兩數之和,都是用這種先暴力然後思考暴力法低效的原因(每一次對後區間的遍歷沒有給下一次提供有用的資訊導致的)從而得到最佳化的方法(遍歷過的節點需要給下一次遍歷提供有意義的資訊)。

相關文章