# 【5-0】複雜度估計法 複雜度是我們用來分析程式碼效率的工具,分成「空間複雜度」、「時間複雜度」。 讓我們用簡單的例子來了解: 假設班上 50 位同學,要登記 3 次數學小考成績,我們在 [【3-3】二維陣列](https://hackmd.io/@LAfWxjSxRASps-4O_bppsA/rklX2HZHll) 學習過怎麼處理: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a[3][50]; for(int i=0;i<3;i++){ for(int j=0;j<50;j++){ cin >> a[i][j]; } } return 0; } ``` 你需要在紙上畫 150 格來登記成績,這就叫空間複雜度 你需要寫 150 次成績,這就叫時間複雜度 ## 複雜度 通常,我們都是用最糟情況來估計複雜度,例如抽獎中頭獎,我們當然有可能第一抽就抽中,但最糟糕的情況是抽到最後一次才中。 所以,發明出了 Big O,標記為 $O()$,是上限的意思,該程式碼最糟糕的情況,不會超過這個限制。 ### 空間複雜度 空間複雜度(Space Complexity) 是用來衡量程式在執行時「會額外佔用多少記憶體空間」的。 ### 時間複雜度 時間複雜度(Time Complexity) 是用來衡量「當輸入變大時,程式需要花費多少步驟或時間」來完成執行。 ## 估計法原則 * 忽略所有常數 * 忽略所有的非最高次項 像是 $n^3+2n^2+nlogn+123456$,用big O 標記為$O(n^3)$ 也許在 $n = 1$ 的時候,我們的複雜度估計出來非常不準,但數字拉大來看,確實會接近於 $n^3$,而我們通常會認定 $n$ 很大,因為太小的 $n$ 就算估計不準,對程式運行的效率也不會有太大影響。 ## 怎樣的複雜度才合理 原則上時間複雜度以 $10^8$ 為上限,超過就很難在 1 秒內跑完:空間複雜度的部分比較不會超標,大概抓 $10^8$ 是合理範圍。 ## 常見的時間複雜度 這些方法在之後都會學習到,這邊先看看就好了: | 表記法 | 常見情境範例 | |-------------|-------------------------------| | $O(1)$ | 常數操作、陣列取值 | | $O(\log n)$ | 二分搜尋 | | $O(n)$ | 單一迴圈、線性掃描 | | $O(n \log n)$ | 快速排序、合併排序 | | $O(n^2)$ | 巢狀雙迴圈 | | $O(2^n)$ | 子集合枚舉、暴力遞迴 | | $O(n!)$ | 全排列、暴力搜尋 | ## 複雜度估計練習 例題: ```cpp int a[1000]; // 複雜度O(1) int a[n]; // 複雜度O(n) int b[n][n]; // 複雜度O(n^2) ``` ```cpp for(int i=0;i<n;i++){ // 複雜度O(n) } ``` ```cpp for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ // 複雜度O(n^2) } } ``` 練習題: ```cpp int sum=0; for (int i = 1; i < n; i *= 2) { sum+=i; } ``` <details> <summary>解答</summary> O(log n) </details> <br> ```cpp int f(int n){ if(n == 0) return 0; if(n == 1) return 1; return f(n - 1) + f(n - 2); } ``` <details> <summary>解答</summary> O(2^n) </details> <br> ```cpp int l = 0, r = n - 1; while (l <= r) { int m = (l + r) / 2; if (a[m] == x) break; else if (a[m] < x) l = m + 1; else r = m - 1; } ``` <details> <summary>解答</summary> O(log n) </details> <br> ```cpp int a = 5, b = 7; int c = a * b + 10; ``` <details><summary>解答</summary> O(1) </details> <br> ```cpp int sum = 0; for(int i = 0; i < n; i++){ sum += a[i]; } ``` <details><summary>解答</summary> O(n) </details> <br> ```cpp for(int i = 1; i <= n; i++){ int x = i; while(x > 1){ x /= 2; } } ``` <details><summary>解答</summary> O(n log n) </details> <br> ```cpp void permute(vector<int>& nums, int l, int r) { if (l == r) return; for (int i = l; i <= r; i++) { swap(nums[l], nums[i]); permute(nums, l + 1, r); swap(nums[l], nums[i]); } } ``` <details><summary>解答</summary> O(n!) </details> --- 聯絡方式:codecodefunny@gmail.com 最後編修時間:2025/07/04 子柚筆