1. 程式人生 > >LeetCode程式設計集訓第1次

LeetCode程式設計集訓第1次

一、雜湊表思想

雜湊表,是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。

給定表M,存在函式f(key),對任意給定的關鍵字值key,代入函式後若能得到包含該關鍵字的記錄在表中的地址,則稱表M為Hash表,函式f(key)為Hash函式。

分配地址方法:

1,直接定址法:

函式公式:f(key)=a*key+b (a,b為常數)

這種方法的優點是:簡單,均勻,不會產生衝突。但是需要事先知道關鍵字的分佈情況,適合查詢表較小並且連續的情況。

 

2,數字分析法:

比如我們的11位手機號碼“136XXXX7887”,其中前三位是接入號,一般對應不同運營公司的子品牌,如130是聯通如意通,136是移動神州行,153是電信等。中間四們是HLR識別號,表示使用者歸屬地。最後四們才是真正的使用者號。

若我們現在要儲存某家公司員工登記表,如果用手機號碼作為關鍵字,那麼極有可能前7位都是相同的,所以我們選擇後面的四們作為雜湊地址就是不錯的選擇。


3,平方取中法:

故名思義,比如關鍵字是1234,那麼它的平方就是1522756,再抽取中間的3位就是227作為雜湊地址。


4,摺疊法:

摺疊法是將關鍵字從左到右分割成位數相等的幾個部分(最後一部分位數不夠可以短些),然後將這幾部分疊加求和,並按雜湊表表長,取後幾位作為雜湊地址。

比如我們的關鍵字是9876543210,雜湊表表長三位,我們將它分為四組,987|654|321|0 ,然後將它們疊加求和987+654+321+0=1962,再求後3位即得到雜湊地址為962,哈哈,是不是很有意思。


5,除留餘數法:

函式公式:f(key)=key mod p (p<=m)m為雜湊表表長。

這種方法是最常用的雜湊函式構造方法。


6,隨機數法:

函式公式:f(key)= random(key)。

這裡random是隨機函式,當關鍵字的長度不等是,採用這種方法比較合適。

二、例題

1、兩數之和(1)

給定一個整數陣列 nums 和一個目標值 target

,請你在該陣列中找出和為目標值的那 兩個 整數,並返回他們的陣列下標。

你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個陣列中同樣的元素。

示例:

給定 nums = [2, 7, 11, 15], target = 9

因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

分析:為了對執行時間複雜度進行優化,我們需要一種更有效的方法來檢查陣列中是否存在目標元素。如果存在,我們需要找出它的索引。保持陣列中的每個元素與其索引相互對應的最好方法就是雜湊表。

通過以空間換取速度的方式,我們可以將查詢時間從 O(n)O(n)O(n) 降低到 O(1)O(1)O(1)。雜湊表正是為此目的而構建的,它支援以 近似 恆定的時間進行快速查詢。我用“近似”來描述,是因為一旦出現衝突,查詢用時可能會退化到 O(n)O(n)O(n)。但只要你仔細地挑選雜湊函式,在雜湊表中進行查詢的用時應當被攤銷為 O(1)O(1)O(1)。

一個簡單的實現使用了兩次迭代。在第一次迭代中,我們將每個元素的值和它的索引新增到表中。然後,在第二次迭代中,我們將檢查每個元素所對應的目標元素(target−nums[i]target - nums[i]target−nums[i])是否存在於表中。注意,該目標元素不能是 nums[i]nums[i]nums[i] 本身!

程式碼:

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        if not nums:
            return None
            
        d = {}   
        for i, item in enumerate(nums):
            tmp  = target - item      #迴圈取nums裡面的值與target作差
            
            for key, value in d.items():#尋找差值是否存在hash表裡
                if value == tmp:
                    return [key, i] #如果存在,返回對應的key和i
            
            d[i] = item   #把nums裡的值新增進hash表中
            
        return None 

 

 

 

 

 

2、快樂數(202)

編寫一個演算法來判斷一個數是不是“快樂數”。

一個“快樂數”定義為:對於一個正整數,每一次將該數替換為它每個位置上的數字的平方和,然後重複這個過程直到這個數變為 1,也可能是無限迴圈但始終變不到 1。如果可以變為 1,那麼這個數就是快樂數。

示例: 

輸入: 19
輸出: true
解釋: 
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

分析1:不是快樂數的數稱為不快樂數(unhappy number),所有不快樂數的數位平方和計算,最後都會進入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 的迴圈中,快樂數最終sum都會為1

方法一程式碼:

class Solution:
    
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        self.base = {4, 16, 37, 58, 89, 145, 42, 20}
        sums = sum(map(lambda x:x**2, map(int, str(n)))) #逐位平方相加
        if sums in self.base:
            return False
        if sums == 1:
            return True
        else:
            return self.isHappy(sums)  #迴圈

分析2:如果n是快樂數它將不會進入迴圈,進入迴圈的就不是快樂數

方法二程式碼:

class Solution:
    def __init__(self):
        self.hash_dict={}
    
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        sums = sum(map(lambda x:x**2, map(int, str(n)))) #逐位平方相加
        if sums == 1:
            return True
        if sums in self.hash_dict:
            return False
        else:
            self.hash_dict[sums]=0
        return self.isHappy(sums)  #迴圈