# 【6-0】演算法介紹 演算法(Algorithm) 是指一組「清楚定義的步驟」或「處理流程」,用來有效解決某一類問題。在程式語言的世界中,演算法不只是解題的工具,更是影響「程式效率」的關鍵因素。 - 語法讓你寫出可以執行的程式 - 邏輯賦予程式功能 - 演算法讓程式有效率、巧妙的解決問題 在[【5-0】複雜度估計法](https://hackmd.io/@LAfWxjSxRASps-4O_bppsA/B1bcXCEHgx) 我們已經學習過複雜度估計法,而複雜度正是演算法當中評斷好與壞的重要指標。 前四章學習的是基礎語法、邏輯,第五章學習的是複雜度低的工具,現在我們要把前五章學習到的內容組合起來,成為演算法。 ## 範例 給定一個長度為 `n` 的整數陣列 `a[0…n-1]`,請找出一個連續子陣列,使其所有元素和最大,並輸出這個最大和。 例如,對陣列 `[-2, 1, -3, 4, -1, 2, 1, -5, 4]`,最大連續子陣列是 `[4, -1, 2, 1]`,其和為 `6`。 ### 解法 1:三層迴圈暴力枚舉 最直觀的方法,枚舉所有可能的起點 `i` 和終點 `j`,累加 `a[i] + a[i+1] + … + a[j]`,並維護最大值。 ```cpp= int maxSubArray(vector<int>& a) { int n = a.size(); int best = INT_MIN; // O(n²)枚舉子陣列 for (int i = 0; i < n; ++i) { for (int j = i; j < n; ++j) { // O(n)區間和 int sum = 0; for (int k = i; k <= j; ++k) { sum += a[k]; } best = max(best, sum); } } return best; } ``` * **時間複雜度**:O(n³) ### 解法 2:前綴和 + 雙層枚舉 利用前綴和(prefix sum)陣列 `ps`,使每次區間和計算從 O(n) 降到 O(1)。 1. 先建 `ps[0] = 0`,`ps[i] = a[0] + … + a[i-1]`。 2. 區間 `i…j` 的和就是 `ps[j+1] - ps[i]`。 ```cpp= int maxSubArray(vector<int>& a) { int n = a.size(); // O(n)前綴和 vector<int> ps(n + 1, 0); for (int i = 0; i < n; ++i) ps[i + 1] = ps[i] + a[i]; int best = INT_MIN; // O(n²)枚舉子陣列 for (int i = 0; i < n; ++i) { for (int j = i; j < n; ++j) { // O(1)區間和 int sum = ps[j + 1] - ps[i]; best = max(best, sum); } } return best; } ``` * **時間複雜度**:O(n²) --- ### 解法 3:Kadane’s Algorithm(線性掃描) Kadane 演算法只需一次掃描,就能在 O(n) 內解出最大和。思路是: 1. 設 `curr = a[0]`, `best = a[0]` 2. 每向右移一格 `i`,更新 ``` curr = max(a[i], curr + a[i]); best = max(best, curr); ``` 其中 `curr` 代表「以 i 結尾的最大子陣列和」。 ```cpp= int maxSubArray(vector<int>& a) { int n = a.size(); int curr = a[0], best = a[0]; // O(n)線性掃描找以 i 結尾的最大子陣列和 for (int i = 1; i < n; ++i) { curr = max(a[i], curr + a[i]); best = max(best, curr); } return best; } ``` * **時間複雜度**:O(n) ## 結論 在接下來的單元,我們將著重介紹各類演算法的思路,並提供範例來講解演算法在題目中的應用,比較同一題的各類演算法效率,建議讀者熟讀第五章及以前的所有內容,再來看演算法。 --- 聯絡方式:codecodefunny@gmail.com 最後編修時間:2025/08/02 子柚筆