iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
ChatGPT & Codex

從 Prompt Engineering 到 Copilot / Codex 實務 30 天系列 第 7 篇

Day 07:【複雜度分析】向 AI 請教:如何評估演算法的時間複雜度(Big-O)與空間複雜度?

  • 分享至 

  • xImage
  •  

昨天我們透過「破題引導提問法」,學會了在寫代碼前先挖掘約束與邊界條件。然而在實際面試或工程場景中,寫出正確解答只是及格線,面試官或架構審查最常接著問的一句話往往是:

「請問你這段代碼的時間複雜度與空間複雜度是多少?能再優化嗎?」

許多開發者對於漸進符號(Big-O Notation)的直覺往往只停留在「一層迴圈是 O(n)、兩層是 O(n²)」。一旦遇到遞迴(Recursion)、二分搜尋(Binary Search)或涉及集合動態擴容(Dynamic Array Resizing)時,就很難給出精確評估。

今天我們就來探討:如何利用 ChatGPT 作為演算法助教,逐行拆解時間與空間開銷,精準掌握複雜度推導邏輯。


一、複雜度分析提問模板(Analysis Prompting)

當你寫完一段解法,或想評估別人的代碼時,不要只問「這段複雜度是多少?」,而是要求 AI 依照「計算機科學的嚴謹步驟」逐步拆解:

【複雜度分析提示詞範本】
請扮演計算機演算法助教。請針對以下代碼進行詳細的複雜度評估:
[貼上代碼區塊]

請依序回答以下四點:

  1. 時間複雜度(Time Complexity):請逐行指出關鍵耗時操作,並給出最差情況(Worst Case)、最好情況(Best Case)與平均情況(Average Case)的 Big-O 評估。
  2. 空間複雜度(Space Complexity):區分固定開銷與額外輔助空間(Auxiliary Space),包含遞迴呼叫堆疊(Call Stack)的深度開銷。
  3. 隱形代價提醒:是否有容易被忽視的內建函式開銷(如 String 拼接、陣列擴容或 Collection 操作)?
  4. 極限優化建議:在當前複雜度下,是否有常數級別(Constant Factor)或資料結構上的降維優化空間?

二、實戰案例:看似 O(n) 實則 O(n²) 的字串處理陷阱

很多時候我們以為代碼只有一層迴圈,時間複雜度就是線性 O(n),但其實暗藏隱形開銷。

[實測問題範例]
給定一個字串清單,將所有單字組裝成一個由逗號分隔的句子:

[Java 初學者常見解法]
public class StringConcatDemo {
public static String buildSentence(String[] words) {
String result = "";
for (int i = 0; i < words.length; i++) {
result += words[i]; // 每次字串相加
if (i < words.length - 1) {
result += ",";
}
}
return result;
}
}


三、AI 的逐步複雜度推導

將這段代碼交給 AI 依模板分析後,得到的深度剖析如下:

1. 時間複雜度拆解(深層陷阱)

  • 表面直覺:只有一個長度為 n 的 for 迴圈,直覺猜測為 O(n)。
  • 實際底層:在 Java 中,String 是不可變物件(Immutable)。每次執行 result += words[i],背後其實是在記憶體中配置一個全新長度的字元陣列,並將舊字串的所有字元複製過去。
  • 總步數計算:若每個單字平均長度為 L,第 k 次拼接需複製 k * L 個字元。
    總運算量為 L + 2L + 3L + ... + nL = O(L * n²)。
  • 結論:時間複雜度實際為 O(n²),在大量字串處理時會引發嚴重的 CPU 與 GC 負擔!

2. 空間複雜度拆解

  • 額外空間開銷:迴圈執行過程中會產生大量短命的中間字串物件(Intermediate String Objects),對記憶體新生代(Young Generation)造成高壓,輔助空間開銷同樣高達 O(n²)。

四、AI 的優化重構與複雜度對照

透過 AI 指出瓶頸後,我們要求它提供最優解法,並重新評估:

[Java 優化解法:使用 StringBuilder]
public class StringConcatOptimized {
public static String buildSentence(String[] words) {
if (words == null || words.length == 0) {
return "";
}

    // 預先估算容量,減少內部 char[] 擴容次數
    StringBuilder sb = new StringBuilder(words.length * 10);
    for (int i = 0; i < words.length; i++) {
        sb.append(words[i]);
        if (i < words.length - 1) {
            sb.append(",");
        }
    }
    return sb.toString();
}

}

優化後成果:

  • 時間複雜度:降為嚴格的 O(N)(其中 N 為所有字元的總長度),因為 StringBuilder append 是均攤 O(1) 的操作。
  • 空間複雜度:降為 O(N),只保留最終輸出結果,消除了大量垃圾物件。

五、工程師的評估心法

透過 AI 分析複雜度時,請記住以下三條心法:

  1. 不要只看迴圈層數:務必請 AI 檢視「呼叫到的內建方法內部做什麼」(例如 list.contains() 是 O(n),set.contains() 才是 O(1))。
  2. 注意遞迴堆疊:遞迴呼叫的空間複雜度並非 O(1),最大遞迴深度(Call Stack Depth)就是額外的空間複雜度。
  3. 掌握時空權衡(Trade-off):優化時間往往需要犧牲空間(如 HashMap),而節省空間往往需要更多遍歷運算,沒有絕對的好壞,端看運行環境資源。

今日小結與預告

今天我們掌握了利用 AI 深度推導時間與空間複雜度的架構化流程,學會了揪出看似線性但實則平方級別的隱形開銷。


上一篇
Day 06:【LeetCode 破題】拒絕死背解答:引導 ChatGPT 先梳理題目條件與邊界條件
下一篇
Day 08:【陣列與雙指針】用 AI 拆解經典陣列題:從暴力解一步步優化到雙指針法
系列文
從 Prompt Engineering 到 Copilot / Codex 實務 30 天 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言