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) #迴圈