· Joseph · Online Course  · 5 min read

Algorithm - hash map and set

import { YouTube } from 'astro-embed';

Set and Map 平常就有在用,map存的是Key-value pair、Set存的是unique value。而且操作上來說平均都是O(1)時間複雜度。這篇就來看看他們適合解哪些題型吧。

Set and Map 平常就有在用,map存的是Key-value pair、Set存的是unique value。而且操作上來說平均都是**O(1)**時間複雜度。這篇就來看看他們適合解哪些題型吧。

TOC

Map vs. Set

特性Hash Map(雜湊表 / 字典)Hash Set(雜湊集合)
核心概念Key–Value Pair的集合唯一元素(Unique Keys)的集合
儲存內容儲存 (Key, Value),Key 不可重複,Value 可重複僅儲存 Key,且 Key 不可重複(自動去重)
主要用途當你需要建立「A 對應到 B」的關係時
例如:統計頻率、儲存原始索引
當你只需要知道「某物是否存在」或「去重」時
例如:判斷是否看過該數字、過濾重複名單
存取方式透過 Key 來存取對應的 Value
map.get(key) → value
僅能查詢某元素 Key 是否存在
set.contains(key) → true / false
常見操作put(key, value)
get(key)
containsKey(key)
add(key)
remove(key)
contains(key)
時間複雜度新增 / 查詢 / 刪除:平均皆為 O(1)新增 / 查詢 / 刪除:平均皆為 O(1)
程式語言範例Pythondict, {k: v}Pythonset, {k}

Pair Sum - Unsorted

關鍵在於把data 當成 key、把index 當成 value,然後找每個data的補數(target - data)有沒有在map的key裡,有的話把補數的value抓出來,也就是補數的index了。

Play
from typing import List

def pair_sum_unsorted(nums: List[int], target: int) -> List[int]:
    # Write your code here
    hash_map = {}
    for i, x in enumerate(nums):
        complementary = target - x
        if complementary in hash_map:
            return [hash_map[complementary], i]
        hash_map[x] = i
    return []

Verify Sudoku Board

驗證sudoku board關鍵在

  1. row 要有9個set
  2. col 要有9個set
  3. 每個3x3 subgrid 都要有1個set,所以對3x3 subgrid共要有9個set

for-loop兩層去看每個[i][j] 的cell,其row-i, col-j 跟 subgrid-i-j 的 set有沒有重複的值。

Play
from typing import List

def verify_sudoku_board(board: List[List[int]]) -> bool:
    row_set = [set() for i in range(9)]
    col_set = [set() for i in range(9)]
    # i // 3 * 3 + j // 3 
    subgrid = [set() for i in range(9)]

    for i in range(9):
        for j in range(9):
            num = board[i][j]
            if num == 0:
                continue

            if num in row_set[i]:
                return False
            if num in col_set[j]:
                return False
            if num in subgrid[i // 3 * 3 + j // 3]:
                return False
            row_set[i].add(num)
            col_set[j].add(num)
            subgrid[i // 3 * 3 + j // 3].add(num)

    return True

Zero Striping

Zero striping重點是要跑兩次nested loop (m * n),第一次要找出0所在的(i, j),分別存入row跟col的set。第二次loop就把 (i, j) 中如果irow setjcol set則把 (i, j) 設為 0

Play
from typing import List

def zero_striping(matrix: List[List[int]]) -> None:
    m = len(matrix)
    if m == 0:
        return
    n = len(matrix[0])
    if n == 0:
        return   
    row_set = set()
    col_set = set()

    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 0:
                row_set.add(i)
                col_set.add(j)
    for i in range(m):
        for j in range(n): 
            if j in col_set:
                matrix[i][j] = 0
            if i in row_set:
                matrix[i][j] = 0

Longest Chain of Consecutive Numbers

這題我的解法跟ByteByteGo就不太一樣,影片是ByteByteGo的做法

Play

我是跑2次loop,第1次找出head_set,然後第二次針對 head_set 每個去逐步 +1,找出最長的Consecutive Numbers

from typing import List

def longest_chain_of_consecutive_numbers(nums: List[int]) -> int:
    chain_head_set = set()

    for x in nums:
        if not x - 1 in nums:
            chain_head_set.add(x)

    largest_chain = 0
    for head in chain_head_set:
        current = head
        current_chain = 1
        if current + 1 in nums:
            while current + 1 in nums:
                current += 1;
                current_chain += 1
        largest_chain = current_chain if current_chain > largest_chain else largest_chain
    
    return largest_chain

Geometric Sequence Triplets

這題的關鍵是出現的頻率相乘後相加,就是總共有幾個 Geometric Sequence Triplets。 但還有一個關鍵是,要找出 x/r, x, x*r 的組合。然後以xcurrent_value,計算出左邊map右邊mapdata的的頻率,才能相乘跟累加。

Play
from typing import List

def geometric_sequence_triplets(nums: List[int], r: int) -> int:
    left_hash = dict()
    right_hash = dict()
    for i in nums:
        right_hash[i] = right_hash[i] + 1 if i in right_hash else 1
    
    count = 0;
    for i in nums:
        if not i in left_hash:
            left_hash[i] = 0
        right_hash[i] -= 1
        if i % r == 0:
            count += left_hash.get(i / r, 0) * right_hash.get(i * r, 0)
        left_hash[i] += 1
    
    return count

Conclusion

以前都沒想過可以用SetMap去解題,都把它當成很單純的資料結構在存。現在知道針對這些頻率重複、或需要 key-value pair做應用的,都可以用Set or Map去處理。

If you like this post, please connect with me on LinkedIn and give me some encouragement. Thanks.

Related Posts

View All Posts »

Two Pointers Algorithm

import demo from './demo.mp4'; import triplet from './triplet.mp4'; import palindrome from './palindrome.mp4'; import largest_container from './largest_container.mp4'; import shift_zero from './shift_zero.mp4'; import next_permutation from './next_permutation.mp4'; 最近買了ByteByteGo裡的Lifetime Plan方案,才把Coding interview patterns裡的Two pointers algorithm跟System design interview裡的Design A Rate Limiter念完,就先用這篇來筆記一下Two pointers algorithm

System design - Consistent hashing

System design - Consistent hashing

ByteByteGo這篇介紹的是一致性雜湊,一般來說會用到雜湊,目的是為了把流量透過固定的演算法,分散到某台機器上面,那什麼是一致性雜湊,不好的雜湊演算法又會有什麼問題呢?這篇筆記來說一下ByteByteGo怎麼介紹的。

System design - A rate limiter

System design - A rate limiter

這篇要介紹的是Rate Limiter,是ByteByteGo System design裡面第一個design環節。現在很多後端主流框架都有內建或有對應套件,但對應的演算法卻被封裝起來,知其然不知其所以然。 今天這篇靠AI生成點簡單的示意圖,讓一張圖道盡千言萬語。

use-device-camera

use-device-camera

在用了Javascript串webcam一年之後,我做了這個use-device-camera的react npm package。