目錄

C++ 演算法面試常函式

簡介

這邊介紹我自己在解題會用到的小抄以及解題想法。

解題思路

  1. 看題目:先想資料範圍、資料儲存形式、正負與大小會不會有影響、加總、乘積會不會超過 INT_MAX 等,這個是當下要跟面試官討論的部分
    1. 想題目的 edge case
    2. Overflow
  2. 先講暴力破解方法,並且分析時間跟空間複雜度
  3. 開始想資料結構和演算法優化
    1. One-pointer
      • Greedy
      • Prefix sum
    2. Two-pointer
      • 兩邊慢慢集中到中間
      • Sliding window
      • 快慢指標
    3. Sort
      • Binary search
    4. Divide and Conquer
    5. DP
      • Retrieve
      • Top-down/Bottom-up

常用資料結構

以下先提供各種小抄:

情況 適用
要自動排序 set / map
不在乎順序、只求快 unordered_set / unordered_map
允許重複 key multi*
要 key → value map
只有 key set
資料結構 取值 (Index) 搜尋 插入 刪除 get min/max
陣列 (array)
O(1)
O(n)
動態陣列 (vector)
O(1)
O(n)
O(n)
O(n)
O(n)
雙向串列 (list)
O(n)
O(n)
O(1)
O(1)
O(n)
紅黑樹 (set)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
紅黑樹 (multiset)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
Hash table (u_set)
O(1)
O(1)
O(1)
O(1)
O(n)
Hash table (u_multiset)
O(1)
O(1)
O(1)
O(1)
O(n)
紅黑樹 (map)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
紅黑樹 (multimap)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
Hash table (u_map)
O(1)
O(1)
O(1)
O(1)
O(n)
Hash table (u_multimap)
O(1)
O(1)
O(1)
O(1)
O(n)
stack
O(n)
O(n)
O(1)
O(1)
O(n)
queue
O(n)
O(n)
O(1)
O(1)
O(n)
Binary heap (PQ)
O(n)
O(log n)
O(log n)
O(1)
資料結構 取值 (Index) 搜尋 插入 刪除 get min/max
陣列 (array)
O(1)
O(n)
動態陣列 (vector)
O(1)
O(n)
O(n)
O(n)
O(n)
雙向串列 (list)
O(n)
O(n)
O(1)
O(1)
O(n)
紅黑樹 (set/map)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
Hash table (u_*)
O(1)
O(1)
O(1)
O(1)
O(n)
stack / queue
O(n)
O(n)
O(1)
O(1)
O(n)
Binary heap (PQ)
O(n)
O(log n)
O(log n)
O(1)
資料結構類型 資料結構 核心應用場景與特性 經典 LeetCode 例子 / 備註
線性容器 vector 隨機存取 (Index)、排序後處理、雙指標 (Two Pointers) 3Sum, Merge Intervals, 前綴和應用
deque 兩端快速進出、Sliding Window (找區間最值)、0-1 BFS Sliding Window Maximum (239)
有序容器 set Key 唯一、自動排序、動態維護最小/最大值、區間查詢 Contains Duplicate II, 去重 + 排序
multiset 允許重複 Key、自動排序、動態中位數、排行統計 Find Median from Data Stream (295)
map 按 Key 排序輸出結果、區間統計 My Calendar 系列, 頻率排序後輸出
multimap 幾乎不用,建議改用 map<K, vector<V>> 方便對單一 Key 的多個 Value 進行批次處理
無序容器 u_set 快速存在性檢查、去重、循環檢測 Two Sum, Happy Number, Detect Cycle
u_map 頻率統計、計數、哈希映射、子陣列和 (Subarray Sum) Subarray Sum Equals K (560), Anagram
u_multi* 極少見,通常 u_map 搭配 vector 可涵蓋其功能
容器適配器 stack 括號匹配、DFS (迭代版)、表達式計算、單調棧 Valid Parentheses, Daily Temperatures
queue 層序遍歷 (BFS)、緩衝區、生產者消費者模型 Binary Tree Level Order Traversal
priority_queue Top K 元素、排程演算法、多路歸併 Merge k Sorted Lists, Kth Largest Element

stack, queue, and priority_queue

注意 construct heap 是 O(n),但排序整個 heap 是 nlog(n)

常用演算法函式

  1. binary_search, lower_bound, upper_bound

    int a[100]= {4,10,11,30,69,70,96,100};
    int b=binary_search(a,a+9,4);//查找成功,返回1
    cout<<"在数组中查找元素4,结果为:"<<b<<endl;
    int c=binary_search(a,a+9,40);//查找失败,返回0
    cout<<"在数组中查找元素40,结果为:"<<c<<endl;
    int d=lower_bound(a,a+9,10)-a;
    cout<<"在数组中查找第一个大于等于10的元素位置,结果为:"<<d<<endl;
    int e=lower_bound(a,a+9,101)-a;
    cout<<"在数组中查找第一个大于等于101的元素位置,结果为:"<<e<<endl;
    int f=upper_bound(a,a+9,10)-a;
    cout<<"在数组中查找第一个大于10的元素位置,结果为:"<<f<<endl;
    int g=upper_bound(a,a+9,101)-a;
    cout<<"在数组中查找第一个大于101的元素位置,结果为:"<<g<<endl
  2. sort

    std::sort(arr, arr+10, std::greater<int>());
    std::sort(v.begin(), v.end(), [](int a, int b){
        return a < b; // 升序排列
    });
  3. reverse

    reverse(a.begin()+2, a.begin()+6);
  4. next_permutation

    next_permutation(a, a+3);
  5. accumulate(arr.begin(), arr.end(), 0);

演算法

  1. Pointer
    • Two pointers
    • Sliding window
    • Prefix sum
  2. Graph
    • BFS/DFS
    • Union Find
    • Topological Sort
  3. Search
    • Binary Search

其他

Policy-Based Data Structures (PBDS)

GCC 編譯器內建的一套強大擴充庫,雖然它不屬於標準 C++ STL,但因為 Leetcode 是使用 GCC 環境編譯,所以你可以直接調用。

有各種額外的資料結構,像是:

  1. Order Statistic Tree (能查排名的平衡樹),在標準 STL 中,set 只能幫你排序和去重,但它沒辦法在 $O(\log n)$ 時間內告訴你「某個數字是第幾名」或「第 $k$ 大的數字是誰」,PBDS 補足了這個缺憾
  2. gp_hash_table: 比 unordered_map 快非常多的 Hash Table(在某些題目可以避免被惡意測資卡掉)
  3. Priority Queue: 比 STL 的更強大,支持 join(合併兩堆只要 $O(1)$ 或 $O(\log n)$)。

Refernce