演算法與資料結構基礎 - 雜湊表(Hash Table)
Hash Table基礎
雜湊表(Hash Table)是常用的資料結構,其運用雜湊函式(hash function)實現對映,內部使用開放定址、拉鍊法等方式解決雜湊衝突,使得讀寫時間複雜度平均為O(1)。
HashMap(std::unordered_map)、HashSet(std::unordered_set)的原理與Hash Table一樣,它們的用途廣泛、用法靈活,接下來側重於介紹它們的應用。
相關LeetCode題:
706. Design HashMap 題解705. Design HashSet 題解
集合
如果僅需要判斷元素是否存在於某個集合,我們可以使用結構HashSet(std::unordered_set)。例如 LeetCode題目 349. Intersection of Two Arrays:
// 349. Intersection of Two Arrays vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> s1(nums1.begin(),nums1.end()); unordered_set<int> s2(nums2.begin(),nums2.end()); vector<int> res; for(auto& a:s1) if(s2.count(a)) res.push_back(a); return res; }
相關LeetCode題:
349. Intersection of Two Arrays 題解
771. Jewels and Stones 題解202. Happy Number 題解
166. Fraction to Recurring Decimal 題解720. Longest Word in Dictionary 題解
970. Powerful Integers 題解
204. Count Primes 題解36. Valid Sudoku 題解
計數
如果需要對元素進行計數,我們可以使用結構HashMap(std::unordered_map),元素如取值範圍固定可以用Array(std::vector),例如LeetCode題目 217. Contains Duplicate:
// 217. Contains Duplicate bool containsDuplicate(vector<int>& nums) { unordered_map<int,int> m; for(int x:nums) if(m[x]++==1) return true; return false; }
相關LeetCode題:
217. Contains Duplicate 題解811. Subdomain Visit Count 題解
1002. Find Common Characters 題解266. Palindrome Permutation 題解
242. Valid Anagram 題解748. Shortest Completing Word 題解
1072. Flip Columns For Maximum Number of Equal Rows 題解451. Sort Characters By Frequency 題解
347. Top K Frequent Elements 題解454. 4Sum II 題解
781. Rabbits in Forest 題解30. Substring with Concatenation of All Words 題解
在滑動視窗演算法中常使用HashMap計數,關於滑動視窗演算法,詳見:演算法與資料結構基礎 - 滑動視窗(Sliding Window)
Key-Val
進一步地,HashMap表示一種Key-Val (或ID-屬性) 關係,這裡Val可以是計數、下標(index)等等。
相關LeetCode題:
1. Two Sum 題解219. Contains Duplicate II 題解
953. Verifying an Alien Dictionary 題解
359. Logger Rate Limiter 題解1086. High Five 題解
690. Employee Importance 題解981. Time Based Key-Value Store 題解
325. Maximum Size Subarray Sum Equals k 題解244. Shortest Word Distance II 題解
355. Design Twitter 題解
336. Palindrome Pairs 題解
對映
更一般地,HashMap表示一種對映關係,意義在於O(1)時間複雜度完成由 A->B 的對映。
相關LeetCode題:
246. Strobogrammatic Number 題解205. Isomorphic Strings 題解
49. Group Anagrams 題解
249. Group Shifted Strings 題解
290. Word Pattern 題解
138. Copy List with Random Pointer 題解535. Encode and Decode TinyURL 題解
710. Random Pick with Blacklist 題解
HashMap與Prefix sum
利用HashMap和Prefix sum,我們可以在O(n)時間複雜度求解一類子序列求和問題,其中HashMap用於計數,例如LeetCode題目 560. Subarray Sum Equals K:
// 560. Subarray Sum Equals K int subarraySum(vector<int>& nums, int k) { unordered_map<int,int> m; m[0]=1; int sum=0,res=0; for(auto& a:nums){ sum+=a; res+=m[sum-k]; m[sum]++; } return res; }
相關LeetCode題:
560. Subarray Sum Equals K 題解
525. Contiguous Array 題解
930. Binary Subarrays With Sum 題解
325. Maximum Size Subarray Sum Equals k 題解
554. Brick Wall 題解
HashMap與圖形問題
HashMap可以應用於二維圖形的一些問題求解,以尤拉距離、斜率、x/y座標等為key,以計數、x/y座標為val。圖形問題中HashMap的對映關係不是那麼直觀和明顯,需要單獨計算key、仔細甄別對映關係。
相關LeetCode題:
447. Number of Boomerangs 題解
939. Minimum Area Rectangle 題解
149. Max Points on a Line 題解
356. Line Reflection 題解
HashMap與vector/list/stack結合
HashMap與vector、list、stack等資料結構可以結合成為複合資料結構,這樣可以既用到HashMap O(1)的優點,也用到vector支援下標操作、list增刪節點快、stack先進後出的特點。例如 LeetCode題目 380. Insert Delete GetRandom O(1):
// 380. Insert Delete GetRandom O(1) vector<int> v; unordered_map<int,int> m;
以上用vector儲存元素,unordered_map儲存元素和對應下標;getRandom函式利用vector下標操作,而刪除元素時,使用unordered_map取得被刪元素、將vector末尾元素與其對調,利用了HashMap O(1)的優點。
相關LeetCode題:
380. Insert Delete GetRandom O(1) 題解
381. Insert Delete GetRandom O(1) - Duplicates allowed 題解895. Maximum Frequency Stack 題解
146. LRU Cache 題解