Skip to content

巢狀迴圈:迴圈裡面再套一個迴圈

你已經學會三種迴圈工具了:for(跑 N 次)、while(跑到條件不成立)、break/continue(中途控制)。聽起來很完整對吧?

但這個世界有一種問題,單靠一層迴圈解決不了。

為什麼用「逐排貼標籤」來比喻?因為巢狀迴圈的結構跟這個任務完全一樣:都有兩個層次的重複,外層管「哪一排」,內層管「這排裡的每個位子」。想像一下:你是學校的管理員,要幫每排座位貼標籤。教室有 5 排,每排有 6 個座位。你的工作是走到「第 1 排」,然後逐一貼 6 個座位的標籤;貼完第 1 排之後,走到第 2 排,再貼 6 個;依此類推,直到第 5 排貼完為止。

這個任務有兩個層次的重複:「逐排重複」和「每排內逐座位重複」。用一個 for 迴圈只能處理一個層次的重複,處理不了這種「重複裡面還有重複」的結構。

這就是今天要教的巢狀迴圈(Nested Loop)。聽起來有點可怕嗎? ʅ(´◔౪◔)ʃ 其實就是「for 裡面再加一個 for」,五分鐘你就會了。

📷 圖 9:學生要在教室每排每個座位貼標籤的四格漫畫(AI 製圖)

📷 圖 9:學生要在教室每排每個座位貼標籤的四格漫畫(AI 製圖)

💡 📋 學習目標

看完這一節,希望你將能夠:

  1. 寫出雙重 for 迴圈,理解外層控制列、內層控制行的執行順序
  2. 用巢狀迴圈印出直角三角形、長方形、九九乘法表
  3. 在巢狀迴圈中結合 if 條件,找出符合條件的數字對
  4. 培養對巢狀迴圈效能的直覺:外層跑 N 次 × 內層跑 M 次 = 總共 N×M 次
  5. 完成 Judge 解題:直角三角形圖案 + 九九乘法表

知識點 A:雙重 for 迴圈基礎

為什麼需要巢狀迴圈?

先思考一個問題:你想用 for 迴圈列印下面這個圖案:

*
**
***
****
*****

第 1 行印 1 個星號,第 2 行印 2 個,……第 5 行印 5 個。這很像「每行的工作量不同」。

你可以用字串乘法解決這個特定問題:print("*" * i)。但如果印的不是重複的字元,而是要「逐格計算」呢?比方說九九乘法表,每一格的值是 i * j,沒辦法靠字串乘法搞定。這時候你就需要一個「負責每一行的迴圈」:它本身也是迴圈。

為了解釋清楚這個結構,讓我先用一個日常生活的比喻。

你去電影院買票,服務員要幫所有座位做點名。電影院有 3 排,每排 4 個座位。服務員的工作流程是:先進第 1 排,喊 1-1、1-2、1-3、1-4;喊完第 1 排後,進第 2 排,喊 2-1、2-2……以此類推。這個流程有兩層:「逐排循環」(外層)和「每排內逐座位循環」(內層)。

Python 的雙重 for 迴圈,就是在模擬這個流程。讓我們看程式碼。

雙重 for 迴圈的基本語法

先從最簡單的例子開始,讓 Python 印出 3 排 × 4 格的座位編號:

python
for row in range(1, 4):      # 外層:row = 1, 2, 3
    for col in range(1, 5):  # 內層:col = 1, 2, 3, 4
        print(row, col)

輸出結果:

1 1
1 2
1 3
1 4
2 1
2 2
...
3 4

這就是巢狀迴圈的核心概念:外層迴圈每跑一次,內層迴圈就完整跑一遍

來看 Trace Table,追蹤每一步的變數值:

外層 row內層 col輸出
111 1
121 2
131 3
141 4
212 1
222 2
232 3
242 4
313 1
323 2
333 3
343 4

外層 row 跑了 3 次,每次外層 row 前進一格,內層 col 就從頭跑到尾(1→2→3→4)。總共輸出 3 × 4 = 12 行。

直角三角形圖案

學會基本語法後,來印第一個圖案:直角三角形。目標是輸入 N = 4,印出:

*
**
***
****

思考一下:第 i 行要印幾個星號?答案是 i 個。用雙重迴圈,外層控制「第幾行」,內層控制「這行印幾個星號」。程式碼如下:

python
n = int(input())
for i in range(1, n + 1):     # 外層:i = 1, 2, ..., n(第 i 行)
    for j in range(1, i + 1): # 內層:跑 i 次(印 i 個星號)
        print("*", end="")    # end="" 讓星號在同一行
    print()                   # 每行結尾換行

`print("*", end="")`

print() 預設每次都會換行。end="" 讓它改用空字串結尾,也就是不換行。等內層迴圈跑完,外層再呼叫一次沒有參數的 print() 來換行。

Trace Table(以 N = 3 為例):

外層 i內層 j動作
11*,不換行
1(內層結束)換行 → 第 1 行:*
21*,不換行
22*,不換行
2(內層結束)換行 → 第 2 行:**
31*,不換行
32*,不換行
33*,不換行
3(內層結束)換行 → 第 3 行:***

對了!外層 i 決定「這行長度」,內層 j 負責「逐個印出星號」。你可以把外層想成「管理者」,內層想成「執行者」(ฅ'ω'ฅ)

長方形圖案

有了直角三角形,再來一個稍微不同的例子。長方形:每行都有固定數量的星號。輸入兩個數字 R 和 C,印出 R 行、每行 C 個星號。

python
r = int(input())
c = int(input())
for i in range(r):         # 外層:控制行數(共 r 行)
    for j in range(c):     # 內層:每行印 c 個星號
        print("*", end="")
    print()

長方形跟三角形的差別:三角形的內層範圍隨著 i 改變(range(1, i+1)),長方形的內層範圍固定(range(c))。

九九乘法表

現在挑戰稍難一點的:九九乘法表。目標是讓每一格顯示 i * j 的值,格式對齊(每格佔 4 個字元)。在貼程式碼之前,先補兩個會用到的小知識:跳脫字元 \tf-string,看完馬上就用得到。

📌 `\t` 是什麼?跳脫字元(Escape Character)入門

\t 在 Python 字串裡代表 Tab 鍵(定位字元,Tab Character)。當你輸出 "\t",游標會跳到下一個定位點(Tab Stop),這就是表格類輸出能排得整齊的祕密。

字串裡用反斜線 \ 開頭的特殊符號,有個專有名詞叫跳脫字元(Escape Character)。常見的有:

  • \n:換行(newline)
  • \t:Tab(tab)
  • \\:反斜線本身(避免被當成跳脫字元的開頭)

舉個例子:

python
print("a\tb")   # 輸出:a    b(中間是一段 Tab 距離)
print("a\nb")   # 輸出:a 換行 b

雖然在原始碼裡你看到 \t 是「反斜線」加「t」兩個符號,但 Python 讀字串時會把它合併處理成一個 Tab 字元,不是真的印出 \t (´・ω・`)

📌 f-string 是什麼?字串裡塞變數的便捷寫法

還記得 1-2「類題一:段考成績平均」的提示中偷學過 f"{result:.1f}" 嗎?現在正式介紹這個寫法。

在字串前面加 f(例如 f"Hello, {name}"),大括號 { ... } 裡面可以放變數或運算式,Python 會把它計算後嵌進字串:

python
name = "小明"
print(f"Hello, {name}")          # 輸出:Hello, 小明

a = 7
b = 6
print(f"{a} × {b} = {a * b}")    # 輸出:7 × 6 = 42

大括號裡還能加「格式說明」:f"{value:N}" 中的 :N 代表「這個值至少佔 N 個字元寬,不夠寬就在前面補空白(預設右對齊)」。例如:

  • f"{7:4}"" 7"(前面補 3 個空白,總寬 4)
  • f"{42:4}"" 42"(前面補 2 個空白,總寬 4)
  • f"{1234:4}""1234"(剛好 4 格,不補)

這就是讓表格欄位對齊的常見手法,九九乘法表馬上就會用到 ᕕ( ᐛ )ᕗ

兩個小知識搞定,回來看九九乘法表的程式碼:

python
for i in range(1, 10):         # 外層:i = 1 到 9
    for j in range(1, 10):     # 內層:j = 1 到 9
        print(i * j, end="\t") # \t 讓數字之間以 Tab 對齊
    print()                    # 每行結尾換行

九九乘法表有 9 × 9 = 81 次迭代,Trace Table 只顯示重點部分:

外層 i內層 j計算輸出
111×1=11 (tab)
121×2=22 (tab)
131×3=33 (tab)
1.........
191×9=99 → 換行
212×1=22 (tab)
222×2=44 (tab)
............
989×8=7272 (tab)
999×9=8181 → 換行

九九乘法表,三行程式碼! Σ(゚Д゚)

📷 圖 10:巢狀迴圈執行流程示意圖,外層控制行、內層控制列(AI 製圖)

📷 圖 10:巢狀迴圈執行流程示意圖,外層控制行、內層控制列(AI 製圖)

常見錯誤提醒

⚠️ 縮排錯誤:內層迴圈只跑一次

巢狀迴圈最常見的錯誤是縮排搞錯,讓「應該在外層的語句」跑進了外層,或「應該在內層的語句」跑到了外層。

錯誤示範:

python
for i in range(1, 4):
    for j in range(1, i + 1):
        print("*", end="")
print()  # ❌ 縮排不夠!print() 跑到最外層,只換行一次

正確:

python
for i in range(1, 4):
    for j in range(1, i + 1):
        print("*", end="")
    print()  # ✅ 對齊外層迴圈,每行結尾換行

⚠️ 外層與內層變數名稱撞名

python
for i in range(3):
    for i in range(5):  # ❌ 外層跟內層都用 i!
        print(i)

當你用同一個變數名,內層迴圈會覆蓋外層的 i,導致外層迴圈判斷出錯。外層用 i,內層就用 j,是慣例寫法。如果還有第三層,用 k


知識點 B:巢狀迴圈應用

你現在已經掌握了雙重 for 迴圈的基本語法,能夠處理「行列結構」的問題。但巢狀迴圈的威力不只是印圖案:當你在內層加上 if 條件,或是計算行內的空格數,就能解決更多種類的問題。

接下來,我們把巢狀迴圈跟之前學的 if 條件結合起來,再看一個「需要空格配合」的圖案,最後討論巢狀迴圈的效能直覺。

巢狀迴圈 + 條件判斷:找出符合條件的數字對

有一道典型的計算題:「找出 1 到 N 之間所有滿足 i + j = 10 的整數對 (i, j),其中 i ≤ j。」

思路是:外層控制 i,內層控制 j,然後在內層加 if 判斷。程式碼如下:

python
n = int(input())
for i in range(1, n + 1):     # 外層:i 從 1 到 n
    for j in range(i, n + 1): # 內層:j 從 i 開始(確保 i ≤ j)
        if i + j == 10:        # 條件:兩數之和等於 10
            print(i, j)

以 N = 10 為例,輸出:

1 9
2 8
3 7
4 6
5 5

Trace Table(省略不符合條件的列,只展示觸發 print 的時刻):

外層 i內層 ji+j是否等於 10輸出
112
1......
19101 9
224
2......
28102 8
...............
55105 5

注意內層從 range(i, n+1) 而不是 range(1, n+1) 開始,這是為了確保 i ≤ j,避免重複計算 (1,9) 和 (9,1) 這種「同一對不同順序」的情況。掌握這個「讓 j 從 i 開始」的技巧,很多計數問題都能迎刃而解 ᕦ(ò_óˇ)ᕤ

等腰三角形:空格 + 星號的計算

等腰三角形比直角三角形難一點,因為每行不只有星號,還有前置空格:

    *       ← 第 1 行:4 空格 + 1 個星號
   ***      ← 第 2 行:3 空格 + 3 個星號
  *****     ← 第 3 行:2 空格 + 5 個星號
 *******    ← 第 4 行:1 空格 + 7 個星號
*********   ← 第 5 行:0 空格 + 9 個星號

規律:

  • i 行有 n - i 個空格
  • i 行有 2*i - 1 個星號
python
n = int(input())
for i in range(1, n + 1):
    # 印空格
    for j in range(n - i):
        print(" ", end="")
    # 印星號
    for j in range(2 * i - 1):
        print("*", end="")
    print()  # 換行

同一行裡用了兩個不同的內層迴圈,一個負責空格、一個負責星號,但它們都在同一次外層迭代中執行。這是巢狀迴圈常見的模式。

📷 圖 11:電影院服務員逐排逐座位點名的四格漫畫(AI 製圖)

📷 圖 11:電影院服務員逐排逐座位點名的四格漫畫(AI 製圖)

效能直覺:N×M 次

「老師,巢狀迴圈跑幾次?」這個問題很重要,特別是當 N 很大的時候。

答案很直覺:外層跑 N 次,內層跑 M 次,總共 N×M 次

外層次數(N)內層次數(M)總迭代次數(N×M)
3412
1010100
10010010,000
1,0001,0001,000,000

當 N = 1,000 時,雙重迴圈就跑了一百萬次!這在現在的電腦上通常沒問題,但如果 N = 1,000,000,就需要警惕了。這種「操作次數隨輸入大小成正比」的思維,就是演算法複雜度的入門概念,你在 Ch4 學習搜尋和排序時會更深入接觸。

不用死背這個數字

現在只要記得一個口訣:「巢狀迴圈的工作量是兩層的乘積」。遇到 APCS 題目問「這個程式最多跑幾次」,把兩層迴圈的上限乘起來就是答案。

常見錯誤提醒

⚠️ 忘記每行結尾的 `print()` 換行

這是初學者最常犯的錯:只顧內層的輸出,忘記外層結束後要換行。

python
for i in range(1, 4):
    for j in range(1, i + 1):
        print("*", end="")
# ❌ 所有星號全部擠在同一行:***

記得在外層迴圈的縮排層加上 print()

⚠️ range 的內外層搞混

python
n = 5
for i in range(n):        # 外層:0 到 n-1
    for j in range(i):    # 這行到底是「j 跑 0 到 i-1」嗎?

先用 Trace Table 把 i = 0, 1, 2 時的 j 值列出來,確認跑的次數是否符合你的預期。不確定就先用小 N(比如 N=3)手動追蹤。


Judge 解題實戰:星星直角三角形

題目說明

輸入一個正整數 N,印出高度為 N 的星號直角三角形:第 1 行印 1 個 *,第 2 行印 2 個 *,……第 N 行印 N 個 *

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 20)

輸出格式: 共 N 行,第 i 行有 i 個 *,不含多餘空格

範例一

輸入輸出
3*
**
***

範例二

輸入輸出
5*
**
***
****
*****

老師的建議

先自己動手寫!回憶一下:外層控制第幾行,內層控制這行印幾個星號。

卡關了再往下看。

Step 1:分析 IPO

  • I(Input):讀取正整數 N
  • P(Process):外層迴圈從 1 到 N;內層迴圈從 1 到 i,每次印一個 *
  • O(Output):每行結尾換行

Step 2:寫出程式碼

python
n = int(input())
for i in range(1, n + 1):
    for j in range(1, i + 1):
        print("*", end="")
    print()

Step 3:逐行解讀

  1. n = int(input()) — 讀取 N
  2. for i in range(1, n + 1): — 外層,i 從 1 到 N(控制第幾行)
  3. for j in range(1, i + 1): — 內層,j 跑 i 次(印 i 個星號)
  4. print("*", end="") — 印一個 *,不換行
  5. print() — 這行對齊外層,內層跑完後換行

以 N = 3 為例,逐行驗證:

  • i=1:內層跑 1 次 → 印 * → 換行
  • i=2:內層跑 2 次 → 印 ** → 換行
  • i=3:內層跑 3 次 → 印 *** → 換行

Step 4:常見錯誤排查

  • range(1, i + 1) 寫成 range(i)

    range(i) 從 0 開始,跑 0 到 i-1,共 i 次,印出的數量是對的,但 j 的值是 0 開頭。如果後面需要用到 j 的值(比如印數字),要注意起點。印星號不受影響。

  • print() 放在內層迴圈裡(縮排多一格)

    會變成「每印一個 * 就換行」,結果是每行只有一個 *,無論 N 是多少。


Judge 解題實戰:九九乘法表

題目說明

讀入一個整數 N(1 ≤ N ≤ 9),印出 1×1 到 N×N 的乘法表。每個數字佔 4 個字元寬(右對齊)。

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 9)

輸出格式: 共 N 行,第 i 行為 i×1, i×2, …, i×N 的結果,每個數字右對齊佔 4 個字元

範例一(N = 3):

輸入輸出
3 1 2 3
2 4 6
3 6 9

範例二(N = 5):

輸入輸出
5 1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25

老師的建議

關鍵在於「格式對齊」。每個數字要佔 4 個字元寬,試試 f"{i*j:4}"

Step 1:分析 IPO

  • I(Input):讀取 N
  • P(Process):外層控制第 i 行(i 從 1 到 N),內層計算 i * j(j 從 1 到 N)
  • O(Output):每個數字佔 4 個字元,行尾換行

Step 2:寫出程式碼

python
n = int(input())
for i in range(1, n + 1):
    for j in range(1, n + 1):
        print(f"{i * j:4}", end="")  # :4 讓每個數字右對齊佔 4 格
    print()

Step 3:逐行解讀

  1. n = int(input()) — 讀取 N
  2. for i in range(1, n + 1): — 外層,i 從 1 到 N(控制列)
  3. for j in range(1, n + 1): — 內層,j 從 1 到 N(控制行)
  4. print(f"{i * j:4}", end="") — 計算 i×j,印出並右對齊佔 4 格;end="" 不換行
  5. print() — 內層跑完後換行

格式字串 f"{i * j:4}" 中的 :4 代表「此欄位至少佔 4 個字元,預設右對齊」。數字小的會在前面補空格。

Step 4:常見錯誤排查

  • 忘記格式對齊,直接用 print(i * j, end="\t")

    Tab 對齊在小數字時看起來還 OK,但當數字超過一位 tab 停靠點時就會跑掉。建議用 :4 格式。

  • 兩個迴圈的上限都用 range(1, 10) 而不是 range(1, n + 1)

    這樣 N 的值就沒有意義,永遠印 9×9。記得兩個迴圈的範圍都要跟 N 有關。

📷 圖 12:學生用巢狀迴圈一步步印出乘法表的教學示意圖(AI 製圖)

📷 圖 12:學生用巢狀迴圈一步步印出乘法表的教學示意圖(AI 製圖)


自己動手試試!

來了!六道題目,從基礎到進階,每道都是 APCS 實際出現過的圖案類型 _(´ཀ`」 ∠)_ 加油!

星號長方形

問題情境:小晴在電腦課的期末設計專題中,想用 * 星號拼出各種幾何圖案來裝飾班級的佈告欄。她的第一個目標是印出一個長方形:老師說只要輸入「幾行、幾列」,程式就要自動產生對應的星號陣列。小晴回想起上學期美術課做過的馬賽克拼貼,那時候她一格一格手動貼磁磚,累得手都痠了。現在學會了迴圈,她終於可以讓電腦幫忙重複這些動作。小晴想了想,決定先搞清楚:「外層要跑幾次?內層每次要做什麼?」只要把這兩件事想清楚,兩層迴圈一搭配,長方形就出來了!

🔍 思考引導

🧩 把大問題拆成小問題...

這題乍看很複雜,但可以分成幾個步驟:

  1. 第一步 — 搞懂圖案規律:觀察輸出,長方形每行的內容完全一樣,都是 C 個 *,共有 R 行。
  2. 第二步 — 外層迴圈控制列數:需要跑 R 次,每次代表「印出一整行」。
  3. 第三步 — ???:你覺得在外層迴圈的每一次裡,內層需要做什麼?(提示:每行有 C 個 *

每個步驟單獨來看都不難,難的是把它們串起來!

輸入格式: 第一行:一個正整數 R(1 ≤ R ≤ 20) 第二行:一個正整數 C(1 ≤ C ≤ 20)

輸出格式: 共 R 行,每行恰好 C 個 *,不含多餘空格

範例一

輸入輸出
3
4
****
****
****

範例二

輸入輸出
2
5
*****
*****

範例說明

  1. 第一步:讀入 R=3、C=4。
  2. 第二步:外層迴圈跑第 1 次(第 1 行)→ 內層印 4 個 * → 輸出 ****,換行。
  3. 第三步:外層迴圈跑第 2 次(第 2 行)→ 內層同樣印 4 個 * → 輸出 ****,換行。
  4. 第四步:外層迴圈跑第 3 次(第 3 行)→ 內層同樣印 4 個 * → 輸出 ****,換行。
  5. 結論:外層共跑 3 次,每次內層印 4 個星號,產生 3×4 的長方形。

老師的提示

外層控制行數(跑 R 次),內層控制每行星號數(跑 C 次)。注意兩個 range 的上限是固定值(R 和 C),不會隨著目前跑到第幾行而改變——這正是長方形和三角形的關鍵差異。


星號倒三角形

問題情境:阿峰參加學校的程式設計社,社長每週都會出一道圖案挑戰讓社員練功。這週的題目是:「能不能讓星號從多到少,印出一個倒三角形?」阿峰覺得這題很有趣,因為之前學的直角三角形是從少排到多,現在要反過來。他接受挑戰,輸入 N 之後,第一行要印最多星號、最後一行只剩一個。阿峰在筆記本上把前幾行的星號數量列出來觀察,他發現關鍵在於:每一行的星號數量跟「目前是第幾行」有直接關係,只要把遞減的公式找出來,巢狀迴圈就能搞定!

🔍 思考引導

🧩 把大問題拆成小問題...

這題乍看很複雜,但可以分成幾個步驟:

  1. 第一步 — 外層迴圈控制列數:從第 1 行跑到第 N 行,外層迴圈跑 N 次。
  2. 第二步 — 找出每行星號數的規律:第 i 行要印的星號數是 N-i+1(第 1 行 N 個,第 2 行 N-1 個,依此類推)。
  3. 第三步 — ???:你覺得內層迴圈要怎麼用「N-i+1」這個數字來印出正確數量的星號?

每個步驟單獨來看都不難,難的是把它們串起來!

🔀 試著補完這張流程圖...

下面的流程圖有些步驟被 ??? 遮住了:

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 20)

輸出格式: 共 N 行,第 i 行有 N-i+1 個 *

範例一

輸入輸出
4****
***
**
*

範例二

輸入輸出
2**
*

範例說明

  1. 第一步:讀入 N=4。
  2. 第二步:i=1,本行應印 4-1+1=4 個星號 → 輸出 ****,換行。
  3. 第三步:i=2,本行應印 4-2+1=3 個星號 → 輸出 ***,換行。
  4. 第四步:i=3,本行應印 4-3+1=2 個星號 → 輸出 **,換行。
  5. 第五步:i=4,本行應印 4-4+1=1 個星號 → 輸出 *,換行。
  6. 結論:外層跑 4 次,每次用公式 N-i+1 決定內層要印幾個星號,形成倒三角形。

老師的提示

這題與「等差遞減」直接相關:第 i 行印 N-i+1 個星號。當你設計內層迴圈時,思考 range(N - i + 1) 可以跑幾次——那就是這行要印幾個星號。


等腰三角形

問題情境:小涵在數學課學到等腰三角形,老師說等腰三角形最大的特色就是左右對稱。她忽然想到,如果能用程式把這個幾何概念視覺化,一定很酷。於是她給自己出了一道題:輸入高度 N,就能印出一個以 * 組成的等腰三角形。小涵在草稿紙上先手畫了幾行,發現每行的 * 數量和前面的空格數量都有規律,而且空格數加上星號數的總和似乎有固定的關係。她決定把「第幾行」跟「空格數」和「星號數」的公式找出來,用兩個內層迴圈分工合作,一個負責印空格、一個負責印星號,三角形就完成了!

🔍 思考引導

🧩 把大問題拆成小問題...

這題乍看很複雜,但可以分成幾個步驟:

  1. 第一步 — 外層迴圈控制列數:從第 1 行跑到第 N 行,外層迴圈跑 N 次,每次代表一行。
  2. 第二步 — 計算每行需要的空格數:第 i 行前面有 N-i 個空格(第 1 行最多,最後一行 0 個)。
  3. 第三步 — ???:你覺得第 i 行應該印幾個 *?(提示:對照空格公式,試試 2*i-1

每個步驟單獨來看都不難,難的是把它們串起來!

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 20)

輸出格式: 共 N 行,第 i 行先印 N-i 個空格,再印 2i-1 個 *

範例一(N = 4):

輸入輸出
4 *
***
*****
*******

範例說明

  1. 第一步:讀入 N=4。
  2. 第二步:i=1,空格數 = 4-1 = 3,星號數 = 2×1-1 = 1 → 輸出 *(3 空格 + 1 星號)。
  3. 第三步:i=2,空格數 = 4-2 = 2,星號數 = 2×2-1 = 3 → 輸出 ***(2 空格 + 3 星號)。
  4. 第四步:i=3,空格數 = 4-3 = 1,星號數 = 2×3-1 = 5 → 輸出 *****(1 空格 + 5 星號)。
  5. 第五步:i=4,空格數 = 4-4 = 0,星號數 = 2×4-1 = 7 → 輸出 *******(0 空格 + 7 星號)。
  6. 結論:每行先印 N-i 個空格,再印 2i-1 個星號,兩個數字加起來固定為 N + i - 1,形成等腰對稱。

範例二(N = 3):

輸入輸出
3 *
***
*****

老師的提示

每行有兩個任務:印空格和印星號。常見有兩種寫法:(1) 用兩個內層迴圈分別跑,一個負責印 n-i 個空格、一個負責印 2*i-1 個星號;(2) 用 1-2 學過的字串運算 print(" " * (n-i) + "*" * (2*i-1)) 一行印完,把空格字串跟星號字串串接起來。兩種方法都對,重點是把「行號 i」跟空格數、星號數的公式連結清楚。


數字金字塔

問題情境:阿偉在數學課迷上了數字的排列規律,有一天他在課本上看到巴斯卡三角形,覺得數字排成三角形的樣子非常漂亮。他決定先從簡單的開始練習:如果把「1、1 2、1 2 3、1 2 3 4」這樣的序列一行一行堆疊起來,就會形成一個數字金字塔!他想挑戰自己用程式重現這個圖案:輸入高度 N,程式就自動輸出 N 層的數字金字塔。阿偉拿出筆記本仔細觀察,注意到每行的數字個數等於行號,而且每行都從 1 開始遞增——這個規律就是解題的關鍵!

🔍 思考引導

🧩 把大問題拆成小問題...

這題乍看很複雜,但可以分成幾個步驟:

  1. 第一步 — 外層迴圈控制列數:從第 1 行跑到第 N 行,每次外層迭代代表「印出一整行」。
  2. 第二步 — 內層迴圈印出數字序列:第 i 行要印出 1 到 i 共 i 個數字,數字之間用空格分隔。
  3. 第三步 — ???:你覺得怎麼確保最後一個數字後面不會多出一個空格?(提示:思考什麼時候印空格、什麼時候不印)

每個步驟單獨來看都不難,難的是把它們串起來!

🔀 試著補完這張流程圖...

下面的流程圖有些步驟被 ??? 遮住了:

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 15)

輸出格式: 共 N 行,第 i 行為 1 2 3 ... i

範例一(N = 4):

輸入輸出
41
1 2
1 2 3
1 2 3 4

範例說明

  1. 第一步:讀入 N=4。
  2. 第二步:i=1,內層 j 從 1 到 1,只印 1(唯一數字,不加後置空格)→ 輸出 1,換行。
  3. 第三步:i=2,內層 j=1 印 1 (後置空格),j=2 印 2(不加後置空格)→ 輸出 1 2,換行。
  4. 第四步:i=3,內層依序印 1 2 3 → 輸出 1 2 3,換行。
  5. 第五步:i=4,內層依序印 1 2 3 4 → 輸出 1 2 3 4,換行。
  6. 結論:外層 i 決定這行有幾個數字,內層 j 從 1 印到 i,關鍵是最後一個數字 j==i 時不加空格。

範例二(N = 2):

輸入輸出
21
1 2

老師的提示

外層的行號 i 同時決定了內層要印幾個數字(印到 i 為止)。處理尾巴空格的常用技巧:用 if j < i 判斷「這不是最後一個數字」時才在後面加空格,最後一個數字(j == i 時)就不補空格,這樣行尾就不會留下多餘空白。


菱形圖案

問題情境:小嵐喜歡用程式創作幾何藝術,她之前已經成功印出了直角三角形和等腰三角形,現在她的新挑戰是印出一個菱形!她觀察到菱形的上半部就是一個等腰三角形,下半部是一個倒等腰三角形,兩者共用最寬的中間那行。小嵐想到一個策略:「與其把菱形當成一個整體來硬想,不如把它拆成上下兩半,分別用不同的迴圈處理。」這樣每一半都是她之前學過的三角形圖案,只要搞清楚上半部遞增、下半部遞減的方向,把兩段迴圈接在一起,菱形就完成了!

🔍 思考引導

🧩 把大問題拆成小問題...

這題乍看很複雜,但可以分成幾個步驟:

  1. 第一步 — 上半部等腰三角形:從第 1 行到第 N 行,每行 i 印 N-i 個空格 + 2i-1 個 *(遞增)。
  2. 第二步 — 下半部倒等腰三角形:從第 N-1 行倒回第 1 行,每行 i 印 N-i 個空格 + 2i-1 個 *(遞減)。
  3. 第三步 — ???:你覺得上半部和下半部用同一個迴圈還是兩個迴圈比較清楚?兩個迴圈各自的 range 要怎麼設?

每個步驟單獨來看都不難,難的是把它們串起來!

🔀 試著補完這張流程圖...

下面的流程圖有些步驟被 ??? 遮住了:

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 10,代表菱形的半高,菱形共有 2N-1 行)

輸出格式: 共 2N-1 行,中間行最寬,上下各 N-1 行遞增/遞減

範例一(N = 3,共 5 行):

輸入輸出
3 *
***
*****
***
*

範例說明

  1. 第一步:讀入 N=3,菱形共 2×3-1=5 行。
  2. 第二步(上半部,i=1 到 3):
    • i=1:2 個空格 + 1 個星號 → *
    • i=2:1 個空格 + 3 個星號 → ***
    • i=3:0 個空格 + 5 個星號 → *****(最寬中心行)
  3. 第三步(下半部,i=2 到 1,從中心往下遞減):
    • i=2:1 個空格 + 3 個星號 → ***
    • i=1:2 個空格 + 1 個星號 → *
  4. 結論:上半部用 i 從 1 到 N 遞增,下半部用 i 從 N-1 到 1 遞減,公式相同但方向相反。

範例二(N = 2):

輸入輸出
2 *
***
*

老師的提示

把菱形拆成上下兩個三角形來處理:上半部 for i in range(1, n+1) 印遞增的等腰三角形,下半部 for i in range(n-1, 0, -1) 印遞減的倒三角形。兩個迴圈用同一個公式(N-i 個空格 + 2i-1 個星號),只是遍歷順序相反。


配對計數

問題情境:阿彥在數學課學到「組合計數」,老師出了一道有趣的應用題:「1 到 N 之間,有多少組數字對 (i, j) 的和恰好等於 S?」阿彥覺得用手算太慢又容易出錯,決定寫一個程式來自動計算出答案。他在構思解法時注意到一個細節:為了避免重複計算(像 (3,7) 和 (7,3) 其實是同一對),需要規定 i ≤ j,這樣每一組配對就只會被算到一次。阿彥也發現這道題剛好可以用巢狀迴圈搭配條件判斷來解決,讓他體會到有時候數學公式可以幫你預測答案,而程式則能幫你逐一驗證!

🔍 思考引導

💭 如果用數學來表達...

i+j=S,1ijN

其中 i 是較小的數,j 是較大(或相等)的數。當 i 固定時,j 的值唯一確定為 j=Si。你覺得 j 需要滿足哪些條件才算是一個合法的數字對?(提示:j 必須滿足 ijNj1

🧩 把大問題拆成小問題...

這題乍看很複雜,但可以分成幾個步驟:

  1. 第一步 — 設計計數器:建立一個變數 count = 0 來累計符合條件的數字對。
  2. 第二步 — 外層迴圈遍歷 i:i 從 1 跑到 N,代表數字對中較小的那個數。
  3. 第三步 — 內層迴圈遍歷 j 並判斷:j 從 i 開始(確保 i ≤ j)跑到 N,若 i + j == S,則 count += 1
  4. 第四步 — ???:迴圈結束後,你覺得要輸出什麼?

每個步驟單獨來看都不難,難的是把它們串起來!

輸入格式: 第一行:一個正整數 N(1 ≤ N ≤ 100) 第二行:一個正整數 S(2 ≤ S ≤ 200)

輸出格式: 一個整數,代表符合條件的數字對個數

範例一

輸入輸出
10
10
5

範例說明

  1. 第一步:讀入 N=10,S=10,初始化 count=0。
  2. 第二步:遍歷 i=1 到 10,對每個 i 再遍歷 j=i 到 10,檢查 i+j 是否等於 10。
  3. 第三步:找到的合法數字對為 (1,9)、(2,8)、(3,7)、(4,6)、(5,5),共 5 對。
  4. 第四步:注意 i=6 時 j 需從 6 開始,6+6=12≠10;i=6, j=4 不合法(j<i),所以不計。
  5. 結論:符合 i+j=10 且 1≤i≤j≤10 的數字對有 5 組,輸出 5

範例二

輸入輸出
5
7
2

老師的提示

關鍵在內層迴圈的起點:for j in range(i, n+1) 確保 j ≥ i,避免重複計算同一對數字。如果把條件改成 j = S - i,可以省掉內層迴圈,直接判斷 j 是否在合法範圍內——這是進階思路,但兩種方法都能拿到正確答案。


到這裡,2-4 的內容就全部結束了。你已經解鎖了巢狀迴圈這個強力工具!

本節小結

🎯 重點回顧:

  • 巢狀迴圈:一個迴圈放在另一個迴圈裡,外層每跑一次,內層就完整跑一遍
  • 外層控制行,內層控制列(或外層管理者、內層執行者)
  • 總迭代次數 = 外層次數 × 內層次數
  • end="" + print() 組合:用 end="" 讓同一行內輸出不換行,最後再呼叫 print() 換行
  • 縮排決定歸屬print() 放在外層縮排才能每行換行一次
  • 避免外內層變數同名:習慣上外層用 i,內層用 j

📝 下一節:「模組二總結」:

你已經學完了模組二的全部內容:for 迴圈、while 迴圈、break/continue、巢狀迴圈。下一節是模組二的大複習,會整理一張知識地圖,幫你確認哪裡學紮實了、哪裡還需要加強,然後預告模組三的新挑戰。