🎯 什麼情境該想到我

分工:這張是「看到題目,辨認該用哪個策略」的分類卡。各策略的機制、證明、程式碼 → 分治法、貪婪演算法、動態規劃;具體演算法 → reference/演算法導論/。

當你面對一個計算/最佳化問題、暴力解太慢、想不到更好解法時。先辨認它屬於哪種策略。

⚙️ 怎麼用(辨認問題型態 → 套對應策略)

  1. 分治(Divide & Conquer):能把問題拆成同型的小問題、各自解完再合併 → 如合併排序、快排、二分。
  2. 貪婪(Greedy):每一步都取「當下看起來最好」的選擇即可得全域最佳 → 如區間排程、Huffman。(要能證明貪婪選擇性質)
  3. 動態規劃(DP):有重疊子問題 + 最佳子結構 → 把子問題結果記下來(記憶化/表格),避免重算 → 如背包、最長公共子序列。
  4. 想不到時:先寫暴力解,再找「重複計算」或「可拆解」的結構往上述三類靠。

★ 從題目的「訊號」辨認策略

題目裡出現的訊號優先考慮為什麼
「最多/最少/最大/最小」+「有很多種選法」動態規劃最佳化問題;選法之間常共享子問題
「有幾種方法」動態規劃計數問題幾乎都是 DP
每一步的選擇不會影響之後的選項貪婪但要能證明(見下)
資料可以切成獨立的兩半各自處理分治合併排序、最近點對
輸入已排序,或答案有單調性(「值越大越容易滿足」)二分搜尋(包括對答案二分)每步砍掉一半
「連續子陣列/子字串」+ 某種條件滑動視窗或雙指標O(n) 而不是 O(n²)
「列出所有」組合/排列/路徑回溯(DFS + 剪枝)答案本身就是指數級,只能靠剪枝加速
關係、依賴、連通、路徑圖演算法(BFS、DFS、拓撲排序、最短路徑)先把問題建模成圖

★ 貪婪:一個反例就能推翻

找零問題:硬幣面額 {1, 3, 4},湊出 6 元,最少幾枚?

  • 貪婪(每次拿最大的):4 → 剩 2 → 1 + 1,共 3 枚。
  • 最佳解:3 + 3,共 2 枚。

貪婪在台幣面額 {1, 5, 10, 50} 上是對的,換一組面額就錯了。所以「貪婪看起來很合理」不是證明。

證明貪婪正確的標準方法(交換論證):假設有一個最佳解和貪婪的選擇不同,證明可以把最佳解中的某個選擇換成貪婪的選擇,而結果不會變差。如果換得過去,貪婪就是對的;換不過去,通常就找到了反例。

實務做法:寫一個暴力解,用小輸入(n ≤ 10)大量比對貪婪解和暴力解。對不上就代表貪婪錯了。

★ 動態規劃的四步設計法

  1. 定義狀態:dp[i] 代表什麼?要精確到一句話——「前 i 個物品、容量 j 時的最大價值」。狀態定義錯了,後面全錯。
  2. 寫轉移方程式:dp[i] 怎麼從更小的狀態算出來?通常是「最後一步做了什麼選擇」的所有可能取最佳。
  3. 確定初始值與計算順序:dp[0] 是什麼?計算 dp[i] 時,它依賴的狀態已經算好了嗎?
  4. 複雜度 = 狀態數 × 每個狀態的轉移成本。例如 LCS:狀態 m×n,每個 O(1) → O(mn)。

★ 暴力解 → 最佳解的標準路線

暴力解(列舉所有可能)
  ↓ 發現大量重複計算? → 記憶化(DP)
  ↓ 發現不需要考慮所有可能? → 剪枝(回溯)或貪婪
  ↓ 發現有序或單調? → 二分搜尋
  ↓ 發現內層迴圈在找東西? → 換資料結構(map、heap)把內層降到 O(1) 或 O(log n)

第一步永遠是寫出暴力解:它是正確性的基準,也是找出「哪裡在浪費」的起點。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 貪婪不是萬用——很多問題貪婪會得到次佳解,需要 DP。用小例子驗證。

🔗 相關工具