algorithm complexity big-o master theorem time complexity space complexity

[Algorithm] 複雜度分析

漸進符號

當輸入規模 nn 夠大時,函數的低階項與常數係數對成長趨勢的影響可忽略,只有最高階項決定整體行為。

T(n)=3n2+100n+5000T(n) = 3n^2 + 100n + 5000 為例,n=10000n = 10000 時:

  • 3n2=3×1083n^2 = 3 \times 10^8
  • 100n=106100n = 10^6(僅佔 n2n^2 項的 0.3%)
  • 50005000(可忽略)

因此 T(n)=O(n2)T(n) = O(n^2)n2n^2 項完全主導增長。

化簡規則:

  1. 捨棄常數係數:O(5n)=O(n)O(5n) = O(n)
  2. 捨棄低階項:O(n2+n)=O(n2)O(n^2 + n) = O(n^2)
  3. 不同輸入各自獨立:O(n+m)O(n + m) 不能化簡成 O(n)O(n),因為 mm 可能比 nn

O、Ω、Θ 的差異

  • OO(Big-O):上界,演算法不會比這更慢
  • Ω\Omega(Big-Omega):下界,演算法不會比這更快
  • Θ\Theta(Big-Theta):緊界,上界與下界同階
T(n)nn₀c·g(n)f(n)c'·g(n)O(漸進上界)Ω(漸進下界)f(n)(實際函數)n₀ 後,c'·g(n) ≤ f(n) ≤ c·g(n)(此即 Θ 緊界成立的條件)

Θ\Theta 成立的條件:存在 n0n_0 和正常數 c,cc, c',使得對所有 nn0n \geq n_0

cg(n)f(n)cg(n)c' \cdot g(n) \leq f(n) \leq c \cdot g(n)

以線性搜尋為例:

  • Worst case = O(n)O(n):目標在最後一個位置,要掃完整個陣列
  • Best case = Ω(1)\Omega(1):目標在第一個位置,看一次就找到了
  • Average case = Θ(n)\Theta(n):期望上要跑一半,仍然是線性成長

考試考點:嚴格區分 OOΩ\OmegaΘ\Theta

  • 「Quick Sort 是 O(nlogn)O(n \log n)不精確(worst case 是 O(n2)O(n^2)
  • 「Quick Sort average case 是 Θ(nlogn)\Theta(n \log n)」才正確
  • Big O 只保證上界,看到題目問「緊界(tight bound)」必須寫 Θ\Theta

常見複雜度等級

常數時間 O(1)

執行時間與輸入規模無關。典型範例:陣列 index 存取、hash table 無碰撞時的查找。

對數時間 O(log n)

每步將問題規模砍半(或更大比例)。典型範例:二分搜尋——從 nn 個元素開始,每次排除一半,共 log2n\log_2 n 次。對數成長極緩慢:nn 從 100 萬增至 10 億,log2n\log_2 n 僅從 20 增到 30。

線性時間 O(n)

與輸入規模成正比,需遍歷每個元素至少一次。典型範例:線性搜尋、找最大值、計算陣列總和。許多問題的天然下界就是 Ω(n)\Omega(n)(至少要讀過每個輸入一次)。

線性對數時間 O(n log n)

常見於「對每個元素做 logn\log n 代價的事」或「分而治之、每層合併需要線性代價」的結構。Merge Sort、Heap Sort 屬此等級。比較排序(comparison sort)的理論下界為 Ω(nlogn)\Omega(n \log n)——任何只靠比較來排序的演算法,最壞情況不可能更快。

多項式時間 O(nᵏ)

nn 的某個固定次方。最常見的是 O(n2)O(n^2)O(n3)O(n^3)

O(n2)O(n^2) 通常來自兩層巢狀迴圈,對每個元素都要跑一遍所有其他元素——Bubble Sort、Insertion Sort、Selection Sort 都是。n=1000n = 1000 時大約 10610^6 次操作,還可以接受;n=105n = 10^5 時就是 101010^{10} 次,在現代硬體上大概要幾十秒,很慢了。

O(n3)O(n^3) 常見於三層巢狀迴圈,標準的矩陣乘法就是 O(n3)O(n^3):兩個 n×nn \times n 的矩陣相乘,每個輸出元素要做 nn 次乘加,共 n2n^2 個輸出元素。n=1000n = 1000 的矩陣乘法需要 10910^9 次操作,需要幾秒鐘。

只要 kk 是固定常數,多項式時間演算法在理論上都被認為是「可接受的」——這也是 P 類問題的定義(詳見最後一節)。

指數時間 O(2ⁿ)

通常來自列舉所有子集合(nn 個元素的集合有 2n2^n 個子集)。暴力解背包問題、子集合加總問題屬此等級。n=30n = 30 時已達 10910^9 次,n=50n = 50 完全不可行。

階乘時間 O(n!)

列舉所有排列的代價(nn 個元素有 n!n! 種排列)。暴力解旅行推銷員問題即為此等級。n=12n = 12 時約 4.8×1084.8 \times 10^8n=15n = 15 已超過 101210^{12}

例題:用算式推導迴圈複雜度

直覺「兩層迴圈就是 O(n2)O(n^2)」常常對,但考試要的是算式。內層迴圈的次數會隨外層變化時,必須用 Σ 展開、套求和公式,才算完整推導。

(a) 成長率排序

把下列 8 個複雜度由慢到快排序:

O(n7), O(n2), O(loglogn), O(logn), O(n), O(n!), O(2n), O(1)O(n^7),\ O(n^2),\ O(\log \log n),\ O(\log n),\ O(n),\ O(n!),\ O(2^n),\ O(1)

只要握住三大群組 常數 / 對數 / 多項式 / 指數 / 階乘,再比群內:

O(1)O(loglogn)O(logn)O(n)O(n2)O(n7)O(2n)O(n!)O(1) \subset O(\log \log n) \subset O(\log n) \subset O(n) \subset O(n^2) \subset O(n^7) \subset O(2^n) \subset O(n!)

  • loglogn\log \log nlogn\log n 更慢(對 logn\log n 再取一次對數)
  • 多項式之間比次方:n<n2<n7n < n^2 < n^7
  • 指數勝過所有多項式:對任意固定 kknk/2n0n^k / 2^n \to 0
  • 階乘又勝過指數:2n/n!02^n / n! \to 0(由 Stirling 近似 n!2πn(n/e)nn! \sim \sqrt{2\pi n}(n/e)^n 可知)

(b) 巢狀迴圈的算式推導

下列片段其實是選擇排序的 1-indexed 寫法:

for i := 1 to n-1 do
{
    j := i;
    for k := i+1 to n do
        if (a[k] < a[j]) then j := k;
    swap(a[i], a[j]);
}

以比較次數(內層 if 的執行次數)作為代價單位,逐層拆解:

  • 外層 ii:從 11n1n-1,共 n1n - 1
  • 內層 kk:對每個固定的 iikki+1i + 1 掃到 nn,共 nin - i 次比較
  • 外層每輪末尾的 j:=ij := iswap 都是 O(1)O(1),合計 O(n)O(n),不影響最高階

總比較次數:

T(n)=i=1n1(ni)T(n) = \sum_{i = 1}^{n - 1} (n - i)

做變數代換 =ni\ell = n - i(當 i=1i = 1=n1\ell = n - 1,當 i=n1i = n - 1=1\ell = 1):

T(n)==1n1=1+2++(n1)=(n1)n2T(n) = \sum_{\ell = 1}^{n - 1} \ell = 1 + 2 + \cdots + (n - 1) = \frac{(n - 1)\, n}{2}

展開並加上外層 O(n)O(n)

T(n)=n2n2+O(n)=12n212n+O(n)T(n) = \frac{n^2 - n}{2} + O(n) = \frac{1}{2} n^2 - \frac{1}{2} n + O(n)

取最高階項、捨棄常數係數:

T(n)=O(n2)T(n) = O(n^2)

這個推導是選擇排序 O(n2)O(n^2) 的來源:不論輸入是否有序,內層的 nin - i 次比較無法提前中止,每一輪都要掃完未排序區,所以 best / average / worst 全是 Θ(n2)\Theta(n^2)。對比之下,泡泡排序在已排序輸入上可以用 flag 提前退出,best case 退化成 O(n)O(n)

常見錯誤是寫「外層 nn 次、內層 nn 次,所以 n×n=n2n \times n = n^2」就交卷。這在內層範圍隨外層變化時不嚴謹——老師會扣分,因為 n2n^2常數係數12\frac{1}{2}、不是 11。正確做法必須把 Σ 展開、套等差求和公式。

最壞、最佳、平均情況

同一演算法面對不同輸入,執行時間可能差距很大:

  • Worst case:輸入對演算法最不利的情況。這是 OO 最常對應的場景。
  • Best case:輸入對演算法最有利的情況。這是 Ω\Omega 最常對應的場景。
  • Average case:對所有可能輸入取平均(需要假設輸入分佈)。

Quick Sort 是最具代表性的例子:選一個 pivot 將陣列分成兩部分,遞迴排序。

  • Best / Average case:O(nlogn)O(n \log n):每次 pivot 大概把陣列切成一半,遞迴深度是 logn\log n,每層合計掃 nn 個元素,共 nlognn \log n
  • Worst case:O(n2)O(n^2):每次 pivot 都選到最大或最小值,陣列被切成 1 和 n-1,退化成一層一層剝,遞迴深度變 nn,共 n2n^2。這在已排序的輸入上很容易發生(取決於 pivot 選法)。
演算法BestAverageWorst
Binary SearchO(1)O(1)O(logn)O(\log n)O(logn)O(\log n)
Linear SearchO(1)O(1)O(n)O(n)O(n)O(n)
Bubble SortO(n)O(n)O(n2)O(n^2)O(n2)O(n^2)
Merge SortO(nlogn)O(n \log n)O(nlogn)O(n \log n)O(nlogn)O(n \log n)
Quick SortO(nlogn)O(n \log n)O(nlogn)O(n \log n)O(n2)O(n^2)

Merge Sort 的三種情況全都是 Θ(nlogn)\Theta(n \log n),這讓它在輸入分佈未知時是更穩定的選擇。Quick Sort 在實作上通常比 Merge Sort 快(cache 友好、原地排序),但需要好的 pivot 策略(如隨機選 pivot 或 median-of-three)來避免 worst case。Merge Sort 的代價是需要 O(n)O(n) 的額外空間來合併。

主定理(Master Theorem)

分治法將問題拆成若干較小子問題,遞迴解決後合併結果。這類演算法的時間複雜度通常為:

T(n)=aT ⁣(nb)+f(n),a1,  b>1T(n) = aT\!\left(\frac{n}{b}\right) + f(n), \quad a \geq 1,\; b > 1

  • aa:每次遞迴拆成幾個子問題
  • bb:每個子問題的規模縮小比例(變成 n/bn/b
  • f(n)f(n):每次遞迴的合併/拆分代價

主定理提供直接判定 T(n)T(n) 成長速度的方法。

關鍵值 c=logbac = \log_b a

ncn^c 可以想成遞迴樹總共有多少個葉節點的代價。比較 f(n)f(n)(合併代價)與 ncn^c(遞迴天然代價),誰大誰主導。

T(n) = aT(n/b) + f(n),令 c = log_b(a)Case 1f(n) = O(n^(c-ε))f(n) 比 n^c 成長慢T(n) = Θ(n^c)T(n)=8T(n/2)+O(n²)a=8, b=2, c=3f(n)=O(n²)=O(n^(c-1))→ Θ(n³)Case 2f(n) = Θ(n^c)f(n) 與 n^c 相當T(n) = Θ(n^c log n)Merge SortT(n)=2T(n/2)+O(n)a=2, b=2, c=1→ Θ(n log n)Case 3f(n) = Ω(n^(c+ε))f(n) 比 n^c 成長快T(n) = Θ(f(n))T(n)=T(n/2)+O(n)a=1, b=2, c=0f(n)=O(n)=Ω(n^(0+1))→ Θ(n)

套用流程(四步)

  1. 識別 aabbf(n)f(n)
  2. 計算 c=logbac = \log_b a
  3. 比較 f(n)f(n)ncn^c:誰成長快?
  4. 根據結果對應到 Case 1 / 2 / 3,寫出答案

Case 1:遞迴主導 → T(n)=Θ(nc)T(n) = \Theta(n^c)

條件:f(n)f(n)ncn^c 一個多項式因子,即 f(n)=O(ncε)f(n) = O(n^{c - \varepsilon}),某個 ε>0\varepsilon > 0

手把手T(n)=8T(n/2)+O(n2)T(n) = 8T(n/2) + O(n^2)

步驟計算
1. 識別a=8, b=2, f(n)=n2a = 8,\ b = 2,\ f(n) = n^2
2. 求 ccc=log28=3c = \log_2 8 = 3,所以 nc=n3n^c = n^3
3. 比較f(n)=n2f(n) = n^2nc=n3n^c = n^3ffncn^c 慢一個多項式(n1n^{-1}
4. 判定Case 1,T(n)=Θ(n3)T(n) = \Theta(n^3)

Case 2:勢均力敵 → T(n)=Θ(nclogn)T(n) = \Theta(n^c \log n)

條件:f(n)=Θ(nc)f(n) = \Theta(n^c),兩邊同階。每層遞迴都貢獻類似代價,共 logn\log n 層,所以多一個 log\log

手把手(Merge Sort)T(n)=2T(n/2)+O(n)T(n) = 2T(n/2) + O(n)

步驟計算
1. 識別a=2, b=2, f(n)=na = 2,\ b = 2,\ f(n) = n
2. 求 ccc=log22=1c = \log_2 2 = 1,所以 nc=nn^c = n
3. 比較f(n)=nf(n) = nnc=nn^c = n 同階
4. 判定Case 2,T(n)=Θ(nlogn)T(n) = \Theta(n \log n)

Case 3:合併主導 → T(n)=Θ(f(n))T(n) = \Theta(f(n))

條件:f(n)f(n)ncn^c 一個多項式因子,即 f(n)=Ω(nc+ε)f(n) = \Omega(n^{c + \varepsilon}),另需滿足正則條件(實務上大多成立,不詳述)。

手把手T(n)=T(n/2)+O(n)T(n) = T(n/2) + O(n)

步驟計算
1. 識別a=1, b=2, f(n)=na = 1,\ b = 2,\ f(n) = n
2. 求 ccc=log21=0c = \log_2 1 = 0,所以 nc=1n^c = 1
3. 比較f(n)=nf(n) = nnc=1n^c = 1ffncn^c 快一個多項式
4. 判定Case 3,T(n)=Θ(n)T(n) = \Theta(n)

更多範例對照表

遞迴式aabbc=logbac=\log_b af(n)f(n)CaseT(n)T(n)
Binary search: T(n/2)+O(1)T(n/2) + O(1)120112Θ(logn)\Theta(\log n)
Merge sort: 2T(n/2)+O(n)2T(n/2) + O(n)221nn2Θ(nlogn)\Theta(n \log n)
Strassen: 7T(n/2)+O(n2)7T(n/2) + O(n^2)72log272.81\log_2 7 \approx 2.81n2n^21Θ(nlog27)\Theta(n^{\log_2 7})
T(n/2)+O(n)T(n/2) + O(n)120nn3Θ(n)\Theta(n)
4T(n/2)+O(n2)4T(n/2) + O(n^2)422n2n^22Θ(n2logn)\Theta(n^2 \log n)
3T(n/2)+O(n2)3T(n/2) + O(n^2)32log231.58\log_2 3 \approx 1.58n2n^23Θ(n2)\Theta(n^2)

口訣:比較 f(n)f(n)ncn^cff 慢 → Case 1,答案就是 ncn^c;同階 → Case 2,多一個 log\logff 快 → Case 3,答案就是 f(n)f(n)

主定理不是萬能的,有些遞迴式不在它的適用範圍內。例如 T(n)=2T(n/2)+nlognT(n) = 2T(n/2) + n\log n——f(n)=nlognf(n) = n\log nnc=nn^c = n 大,但差的只是一個 logn\log n 因子(不是多項式因子),所以不滿足 Case 3 也不屬於 Case 2。這類情況要改用遞迴樹法或代入法,結果為 Θ(nlog2n)\Theta(n \log^2 n)

例題:用展開法(不用主定理)推導 T(n)=3T(n/3)+O(n)T(n) = 3T(n/3) + O(n)

為什麼要會展開法:主定理是一個「查表規則」,考試如果老師尚未教到、或題目明說「不得使用主定理」,直接寫結果會被扣分。展開法(又稱 iteration method、substitution by unfolding)是把遞迴式一層一層代入,靠 Σ 求和算出精確階數,屬於第一性原理的推導。

T(1)=1T(1) = 1,且

T(n)=3T(n/3)+cnT(n) = 3\, T(n/3) + c n

其中 cc 為常數,代表合併步驟的線性代價。

第 1 層代入

T(n)=3T(n/3)+cnT(n) = 3\, T(n/3) + c n

第 2 層代入:把 T(n/3)=3T(n/9)+c(n/3)T(n/3) = 3\, T(n/9) + c (n/3) 帶回

T(n)=3[3T(n/9)+cn3]+cn=9T(n/9)+cn+cn=9T(n/9)+2cnT(n) = 3\left[3\, T(n/9) + c\,\frac{n}{3}\right] + c n = 9\, T(n/9) + c n + c n = 9\, T(n/9) + 2 c n

第 3 層代入:把 T(n/9)=3T(n/27)+c(n/9)T(n/9) = 3\, T(n/27) + c (n/9) 帶回

T(n)=9[3T(n/27)+cn9]+2cn=27T(n/27)+cn+2cn=27T(n/27)+3cnT(n) = 9\left[3\, T(n/27) + c\,\frac{n}{9}\right] + 2 c n = 27\, T(n/27) + c n + 2 c n = 27\, T(n/27) + 3 c n

觀察規律:展開到第 kk

T(n)=3kT ⁣(n3k)+kcnT(n) = 3^{k}\, T\!\left(\frac{n}{3^{k}}\right) + k \cdot c n

合併項 kcnk c n 是關鍵——每展開一層,都會再添加一整層的 cnc n 合併代價(因為 33 個子問題每個帶回 c(n/3)c (n/3),加起來剛好又是 cnc n)。

觸底條件:展開到 T(1)T(1) 時停下,即 n/3k=1n / 3^{k} = 1,解得

3k=nk=log3n3^{k} = n \quad \Longrightarrow \quad k = \log_{3} n

代回

T(n)=3log3nT(1)+cnlog3n=n1+cnlog3nT(n) = 3^{\log_{3} n} \cdot T(1) + c n \log_{3} n = n \cdot 1 + c n \log_{3} n

T(n)=n+cnlog3n=Θ(nlogn)T(n) = n + c n \log_{3} n = \Theta(n \log n)

最後一步用到 log3n=lognlog3\log_{3} n = \frac{\log n}{\log 3}log3\log 3 是常數可吸收到大 O 裡。

kk子問題大小子問題個數該層合併代價
0nn11cnc n
1n/3n / 3333c(n/3)=cn3 \cdot c (n/3) = c n
2n/9n / 9999c(n/9)=cn9 \cdot c (n/9) = c n
\vdots\vdots\vdots\vdots
kkn/3kn / 3^k3k3^k3kc(n/3k)=cn3^k \cdot c (n/3^k) = c n
葉層11nnnT(1)=nn \cdot T(1) = n

log3n\log_{3} n 層,每層 cnc n,加上葉層 nT(1)=nn \cdot T(1) = n,總和:

T(n)=n+cnlog3n=Θ(nlogn)T(n) = n + c n \log_{3} n = \Theta(n \log n)

這個結果也和主定理的 Case 2 一致(a=3,b=3,c=log33=1a = 3, b = 3, c = \log_{3} 3 = 1f(n)=n=ncf(n) = n = n^{c},同階 → Θ(nlogn)\Theta(n \log n)),但展開法給出的是推導過程、不是查表。

展開法的關鍵步驟:

  1. 逐層代入 2–3 次,手動寫出前幾步,看出係數規律
  2. 寫出一般式 akT(n/bk)+(合併項之和)a^{k} T(n / b^{k}) + (\text{合併項之和})
  3. 找觸底條件 n/bk=1n / b^{k} = 1,解 kk 通常是 logbn\log_{b} n
  4. 代回求和 並化簡到 Θ\Theta 級別

問題複雜度(簡介)

  • P:能在多項式時間 O(nk)O(n^k)解決的問題(排序、Dijkstra、最大流)
  • NP:能在多項式時間內驗證一個解是否正確的問題
  • NP-complete:NP 中最難的一批——所有 NP 問題都可多項式時間規約到它(TSP、SAT、背包)
  • P ⊆ NP,但 P = NP 尚未證明

常見考法

題型必備技能
成長率排序背牢 O(1)loglognlognnnlognn2nk2nn!O(1) \prec \log\log n \prec \log n \prec n \prec n\log n \prec n^2 \prec n^k \prec 2^n \prec n!
給 code 求複雜度內層會變動 → 用 Σ 展開;i=1ni=n(n+1)2\sum_{i=1}^{n} i = \frac{n(n+1)}{2} 要會背
主定理套用a,b,f(n)c=logbaa, b, f(n) \to c=\log_b a \toffncn^c → Case 1/2/3
展開法推導展 3 層看係數、找觸底 k=logbnk=\log_b n、代回求和
區分 O/Ω/ΘO/\Omega/\Theta「緊界」一定是 Θ\Theta;上界 OO;下界 Ω\Omega
辨識 P / NP / NPCNP-complete 代表「無多項式解」,要走近似或啟發式