APCS Python 程式識讀|自測模式

APCS Python 程式識讀 30 題

每題分為「1. 題目」與「2. 解析」。題目區沒有答案標色;解析預設收合,作答後再點開。

建議先用紙筆追蹤變數、迴圈次數與遞迴呼叫,再查看解析。

第 1 題

1. 題目

給定下列函式 f(),當執行 f(10) 時,最終回傳結果為何?

def f(i):
    if i > 0:
        if (i // 2) % 2 == 0:
            return f(i - 2) * i
        return f(i - 2) * (-i)
    else:
        return 1
  1. 1
  2. 3840
  3. -3840
  4. 執行時導致無窮迴圈,不會停止執行
2. 解析(點擊後顯示)

每次遞迴都讓 i 減少 2,因此呼叫順序為:

f(10) → f(8) → f(6) → f(4) → f(2) → f(0)

f(0)=1。再由內往外乘回來:

f(2)  = 1 × (-2)
f(4)  = (-2) × 4
f(6)  = (-8) × (-6)
f(8)  = 48 × 8
f(10) = 384 × (-10)

共有三個負因數:-2、-6、-10,所以結果為負。

答案:C,-3840。

第 2 題

1. 題目

給定下列程式,若輸出結果為 [1][2][3][5][4][6],程式中的 (?) 應為何?

for i in range(5):
    j = 0
    while (?):
        print(f'[{i + j}]', end='')
        j = j + 2
  1. j < i
  2. j > i
  3. j <= i
  4. j >= i
2. 解析(點擊後顯示)

逐一代入 i=0,1,2,3,4,並觀察 j 從 0 開始,每次增加 2。

i可執行的 j印出 i+j
0
101
202
30、23、5
40、24、6

這正好對應條件 j < i

答案:A,j < i

第 3 題

1. 題目

給定下列函式,已知 f(14)、f(10)、f(6) 分別回傳 25、18、10,空格應填何者?

def f(n):
    if n < 2:
        return n
    else:
        return n + f(?)
  1. (n + 1) // 2
  2. n // 2
  3. (n - 1) // 2
  4. (n // 2) + 1
2. 解析(點擊後顯示)

測試 n // 2

f(14) = 14 + f(7)
      = 14 + 7 + f(3)
      = 14 + 7 + 3 + f(1)
      = 25

f(10) = 10 + 5 + 2 + 1 = 18
f(6)  = 6 + 3 + 1 = 10

三個條件全部吻合。

答案:B,n // 2

第 4 題

1. 題目

下列程式執行完後,輸出結果為何?

Q = [0] * 200
val = 0
count = 0
head = tail = 0

for i in range(1, 31):
    Q[tail] = i
    tail = tail + 1

while tail > head + 1:
    val = Q[head]
    head = head + 1
    count = count + 1

    if count == 3:
        count = 0
        Q[tail] = val
        tail = tail + 1

print(Q[head])
  1. 9
  2. 18
  3. 27
  4. 30
2. 解析(點擊後顯示)

程式每取出三個數時,只把第三個放回佇列尾端,前兩個永久刪除。

第一輪處理 1 到 30 後,留下:

3, 6, 9, 12, 15, 18, 21, 24, 27, 30

接著必須延續原本的 count 狀態繼續模擬,不能把計數器重新開始。持續處理後,最後剩下的元素是 18。

答案:B,18。

第 5 題

1. 題目

程式應輸出以下圖形。在不修改第 4、5 行的前提下,最少需要修改幾行?

    *
   ***
  *****
 *******
*********
1  k = 4
2  m = 1
3  for i in range(5):
4      print(' ' * k, end='')
5      print('*' * m)
6      k = k - 1
7      m = m + 1
  1. 1
  2. 2
  3. 3
  4. 4
2. 解析(點擊後顯示)

空白數量原本是 4,3,2,1,0,已經正確。

星號目前是 1,2,3,4,5,但需要的是 1,3,5,7,9,每次應增加 2。

m = m + 2

只需修改第 7 行。

答案:A,修改 1 行。

第 6 題

1. 題目

整數列表滿足 a[k] = 3k + 1,索引為 0~99。以 value=100 呼叫以下函式,兩個 while 主體分別執行幾次?

def f1(a, value):
    r_value = -1
    i = 0
    while i < 100:
        n1 += 1
        if a[i] == value:
            r_value = i
            break
        i = i + 1
    return r_value

def f2(a, value):
    r_value = -1
    low = 0
    high = 99
    while low <= high:
        n2 += 1
        mid = (low + high) // 2
        if a[mid] == value:
            r_value = mid
            break
        elif a[mid] < value:
            low = mid + 1
        else:
            high = mid - 1
    return r_value
  1. n1=33, n2=4
  2. n1=33, n2=5
  3. n1=34, n2=4
  4. n1=34, n2=5
2. 解析(點擊後顯示)

先找出 100 的索引:

3k + 1 = 100
k = 33

線性搜尋從索引 0 檢查到索引 33,包含兩端,因此是 34 次。

二分搜尋的中點依序為:

49 → 24 → 36 → 30 → 33

共 5 次找到。

答案:D,n1=34, n2=5

第 7 題

1. 題目

以下程式用來計算第 N 個費氏數列值,空格 (a)、(b) 應填何者?

a = 0
b = 1
for i in range(2, N + 1):
    temp = b
    (a)
    a = temp
print((b))
  1. (a) f[i]=f[i-1]+f[i-2] (b) f[N]
  2. (a) a=a+b      (b) a
  3. (a) b=a+b      (b) a
  4. (a) f[i]=f[i-1]+f[i-2] (b) f[i]
2. 解析(點擊後顯示)

每輪開始時,a 是前前項,b 是前一項。

temp = b
b = a + b
a = temp

更新後,a 變成舊的前一項,b 變成新的一項。依題目的索引定義,迴圈結束時應輸出 a

答案:C,b = a + b,最後印出 a

第 8 題

1. 題目

執行 f1(1) 時,下列敘述何者錯誤?

def f1(m):
    if m > 3:
        print(m)
        return
    else:
        print(m)
        f2(m + 2)
        print(m)

def f2(n):
    if n > 3:
        print(n)
        return
    else:
        print(n)
        f1(n - 1)
        print(n)
  1. 印出的數字最大的是 4
  2. f1 一共被呼叫二次
  3. f2 一共被呼叫三次
  4. 數字 2 被印出兩次
2. 解析(點擊後顯示)

呼叫結構如下:

f1(1)
 └─ f2(3)
     └─ f1(2)
         └─ f2(4)

輸出順序為:

1 3 2 4 2 3 1

f1 被呼叫 2 次,f2 也只被呼叫 2 次。

答案:C。

第 9 題

1. 題目

下列程式欲求 76 與 48 的最大公因數,while 內容何者正確?

i = 76
j = 48
while (i % j) != 0:
    ____________
    ____________
    ____________
print(j)
  1. k = i % j
    i = j
    j = k
  2. i = j
    j = k
    k = i % j
  3. i = j
    j = i % k
    k = i
  4. k = i
    i = j
    j = i % k
2. 解析(點擊後顯示)

Euclidean Algorithm(輾轉相除法)的不變量是:

gcd(i, j) = gcd(j, i % j)

因此要先保存餘數,再把 j 移到 i,餘數移到 j

k = i % j
i = j
j = k

答案:A。

第 10 題

1. 題目

下列程式執行後輸出何值?

count = 10

if count > 0:
    count = 11

if count > 10:
    count = 12
    if count % 3 == 4:
        count = 1
    else:
        count = 0
elif count > 11:
    count = 13
else:
    count = 14

if count:
    count = 15
else:
    count = 16

print(count)
  1. 11
  2. 13
  3. 15
  4. 16
2. 解析(點擊後顯示)

第一個 if 使 count=11。第二個 if 成立,再使它變成 12。

12 % 3 = 0,不等於 4,因此內層 else 把 count 設成 0。

Python 中整數 0 是 Falsy(假值),所以最後執行外層 else,得到 16。

答案:D,16。

第 11 題

1. 題目

下列函式欲計算 n!,應如何修改才會得到正確結果?

1. def fun(n):
2.     fac = 1
3.     if n >= 0:
4.         fac = n * fun(n - 1)
5.     return fac
  1. 第 2 行改為 fac = n
  2. 第 3 行改為 if n > 0:
  3. 第 4 行改為 fac = n * fun(n + 1)
  4. 第 4 行改為 fac = fac * fun(n - 1)
2. 解析(點擊後顯示)

階乘的基底條件應為 0! = 1

原程式在 n=0 時仍會遞迴到 -1、-2...,無法停止。將條件改為 n > 0,當 n=0 時會直接回傳初始值 1。

答案:B。

第 12 題

1. 題目

下列函式的 (a)、(b)、(c) 應填哪些數字,才能使 f(4) 輸出 2468

def f(n):
    p = 0
    i = n
    while i >= (a):
        p = 10 - (b) * i
        print(p, end='')
        i = i - (c)
  1. 1, 2, 1
  2. 0, 1, 2
  3. 0, 2, 1
  4. 1, 1, 1
2. 解析(點擊後顯示)

希望 i 依序為 4、3、2、1,因此終點是 1,每次減 1。

再觀察輸出:

i=4 → 10-2×4 = 2
i=3 → 10-2×3 = 4
i=2 → 10-2×2 = 6
i=1 → 10-2×1 = 8

答案:A,(a,b,c)=(1,2,1)

第 13 題

1. 題目

執行 g(4) 後,回傳值為何?

def f(n):
    if n > 3:
        return 1
    elif n == 2:
        return 3 + f(n + 1)
    else:
        return 1 + f(n + 1)

def g(n):
    j = 0
    for i in range(1, n):
        j = j + f(i)
    return j
  1. 6
  2. 11
  3. 13
  4. 14
2. 解析(點擊後顯示)

先算各個函式值:

f(4)=1
f(3)=1+f(4)=2
f(2)=3+f(3)=5
f(1)=1+f(2)=6

range(1,4) 只包含 1、2、3,因此:

g(4)=f(1)+f(2)+f(3)=6+5+2=13

答案:C,13。

第 14 題

1. 題目

下列函式的 else 部分應填何者,才能使 Mystery(9) 回傳 34?

def Mystery(x):
    if x <= 1:
        return x
    else:
        return ____________
  1. x + Mystery(x - 1)
  2. x * Mystery(x - 1)
  3. Mystery(x - 2) + Mystery(x + 2)
  4. Mystery(x - 2) + Mystery(x - 1)
2. 解析(點擊後顯示)

基底為 Mystery(0)=0Mystery(1)=1。若每項等於前兩項相加,就得到:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34

因此第 9 項為 34。

答案:D。

第 15 題

1. 題目

下列程式執行後輸出為何?

a = [1, 3, 5, 7, 9, 8, 6, 4, 2]
n = 9

for i in range(n):
    a[i], a[n-i-1] = a[n-i-1], a[i]

for i in range(n//2 + 1):
    print(a[i], a[n-i-1], end=' ')
  1. 2 4 6 8 9 7 5 3 1 9
  2. 1 3 5 7 9 2 4 6 8 9
  3. 1 2 3 4 5 6 7 8 9 9
  4. 2 4 6 8 5 1 3 7 9 9
2. 解析(點擊後顯示)

第一個迴圈執行完整的 9 次。每一對元素會被交換兩次:

i=0 交換 0、8
i=8 再交換 8、0

所以陣列最後回到原狀。

第二個迴圈依序印:

a[0],a[8] → 1 2
a[1],a[7] → 3 4
a[2],a[6] → 5 6
a[3],a[5] → 7 8
a[4],a[4] → 9 9

答案:C。

第 16 題

1. 題目

下列函式以 F(7) 呼叫後回傳 12,則條件應為何?

def F(a):
    if <condition>:
        return 1
    else:
        return F(a - 2) + F(a - 3)
  1. a < 3
  2. a < 2
  3. a < 1
  4. a < 0
2. 解析(點擊後顯示)

測試條件 a < 0,所有負數回傳 1:

F(0)=F(-2)+F(-3)=2
F(1)=F(-1)+F(-2)=2
F(2)=F(0)+F(-1)=3
F(3)=F(1)+F(0)=4
F(4)=F(2)+F(1)=5
F(5)=F(3)+F(2)=7
F(7)=F(5)+F(4)=7+5=12

答案:D,a < 0

第 17 題

1. 題目

正確等第為:90~100 A、80~89 B、70~79 C、60~69 D、0~59 F。以下程式處理 0~100 時,有幾個分數會判錯?

if s >= 90:
    print('A')
elif s >= 80:
    print('B')
elif s > 60:
    print('D')
elif s > 70:
    print('C')
else:
    print('F')
  1. 20
  2. 11
  3. 2
  4. 10
2. 解析(點擊後顯示)

s > 70 的條件放在 s > 60 後面,因此 71~79 會先被判成 D;70 也會因為 70 > 60 被判成 D。

也就是 70~79 共 10 個分數錯誤。

另外 60 不滿足 s > 60,最後被判為 F,又多 1 個錯誤。

答案:B,共 11 個。

第 18 題

1. 題目

下列程式執行後,count 為何?

maze = [
    [1, 1, 1, 1, 1],
    [1, 0, 1, 0, 1],
    [1, 1, 0, 0, 1],
    [1, 0, 0, 1, 1],
    [1, 1, 1, 1, 1]
]

count = 0

for i in range(1, 4):
    for j in range(1, 4):
        dir = [[-1,0], [0,1], [1,0], [0,-1]]
        for d in range(4):
            if maze[i+dir[d][0]][j+dir[d][1]] == 1:
                count = count + 1
  1. 36
  2. 20
  3. 12
  4. 3
2. 解析(點擊後顯示)

程式會對內部 3×3 的每個位置,檢查上、右、下、左四個鄰居是否為 1。

九個位置分別貢獻:

4, 1, 3
1, 2, 2
3, 2, 2

總和為:

4+1+3+1+2+2+3+2+2 = 20

答案:B,20。

第 19 題

1. 題目

若要印出 6、4、2 個星號的三行圖案,(a) 應為何?

for i in range(4):
    for j in range(i):
        print(' ', end='')
    for k in range(6 - 2*i, (a), -1):
        print('*', end='')
    print('')
  1. 2
  2. 1
  3. 0
  4. -1
2. 解析(點擊後顯示)

range(start, stop, -1) 不包含 stop

若 stop 為 0:

i=0:6,5,4,3,2,1 → 6 次
i=1:4,3,2,1     → 4 次
i=2:2,1         → 2 次
i=3:空          → 0 次

答案:C,0。

第 20 題

1. 題目

下列程式碼是自動計算找零程式的一部分,程式碼中三個主要變數分別為 Total(購買總額)、Paid(實際支付金額)、Change(找零金額)。但是此程式片段有冗餘的程式碼,也就是移除該段程式碼之後不會影響程式的功能。請找出冗餘程式碼的區塊。

Change = Paid - Total

print(f'500 : {(Change-Change%500)//500} pieces')
Change = Change % 500

print(f'100 : {(Change-Change%100)//100} coins')
Change = Change % 100

# A 區
print(f'50 : {(Change-Change%50)//50} coins')
Change = Change % 50

# B 區
print(f'10 : {(Change-Change%10)//10} coins')
Change = Change % 10

# C 區
print(f'5 : {(Change-Change%5)//5} coins')
Change = Change % 5

# D 區
print(f'1 : {(Change-Change%1)//1} coins')
Change = Change % 1
  1. 冗餘程式碼在 A 區
  2. 冗餘程式碼在 B 區
  3. 冗餘程式碼在 C 區
  4. 冗餘程式碼在 D 區
2. 解析(點擊後顯示)

任何整數除以 1 的餘數都為 0:

Change % 1 == 0

最後一行把 Change 設為 0,但程式後面已不再使用它,因此不影響輸出或功能。

答案:D。

第 21 題

1. 題目

執行 G(3,7) 後回傳值為何?

def G(a, x):
    if x == 0:
        return 1
    else:
        return a * G(a, x - 1)
  1. 128
  2. 2187
  3. 6561
  4. 1024
2. 解析(點擊後顯示)

每層遞迴都乘上一個 a,直到 x=0 回傳 1,因此:

G(a,x) = a^x

G(3,7)=3^7=2187

答案:B,2187。

第 22 題

1. 題目

函式目的是找出列表中「大於 x 的最小值」,但程式有誤。哪個呼叫能測出錯誤?

A = [0, 2, 4, 6, 8, 10, 12, 14]

def Search(x):
    high = 7
    low = 0
    while high > low:
        mid = (high + low) // 2
        if A[mid] <= x:
            low = mid + 1
        else:
            high = mid
    return A[high]
  1. Search(-1)
  2. Search(0)
  3. Search(10)
  4. Search(16)
2. 解析(點擊後顯示)

前三個呼叫都有合法答案:

Search(-1) → 0
Search(0)  → 2
Search(10) → 12

但列表中沒有任何值大於 16。程式仍會回傳最後一個元素 14,這不符合函式目的。

答案:D,Search(16)

第 23 題

1. 題目

下列函式的兩個 return 應分別填何者,才能正確計算最大公因數?

def GCD(a, b):
    r = a % b
    if r == 0:
        return ______
    return ______
  1. a, GCD(b,r)
  2. b, GCD(b,r)
  3. a, GCD(a,r)
  4. b, GCD(a,r)
2. 解析(點擊後顯示)

a % b == 0,代表 b 能整除 a,最大公因數就是 b

否則利用:

gcd(a,b) = gcd(b, a%b)

下一層應呼叫 GCD(b,r)

答案:B。

第 24 題

1. 題目

程式執行後,下列何者不一定正確?

p = q = A[0]

for i in range(1, n):
    if A[i] > p:
        p = A[i]
    if A[i] < q:
        q = A[i]
  1. p 是列表最大值
  2. q 是列表最小值
  3. q < p
  4. A[0] <= p
2. 解析(點擊後顯示)

若所有元素都相同,例如:

A = [5,5,5]

則最大值和最小值都為 5,所以只能保證 q <= p,不能保證嚴格小於。

答案:C。

第 25 題

1. 題目

依序輸入 0~9 後,列表 X 的元素依序為何?

def F():
    X = [0] * 10
    for i in range(10):
        X[(i + 2) % 10] = int(input())
  1. 0,1,2,3,4,5,6,7,8,9
  2. 2,0,2,0,2,0,2,0,2,0
  3. 9,0,1,2,3,4,5,6,7,8
  4. 8,9,0,1,2,3,4,5,6,7
2. 解析(點擊後顯示)

每個輸入會存到索引 (i+2)%10

輸入 0 → X[2]
輸入 1 → X[3]
...
輸入 7 → X[9]
輸入 8 → X[0]
輸入 9 → X[1]

因此最後為 [8,9,0,1,2,3,4,5,6,7]

答案:D。

第 26 題

1. 題目

原程式無法正確列印 20 次 Hi!。下列哪個修改仍無法列印 20 次?

for i in range(0, 101, 5):
    print('Hi!')
  1. 改為 range(0,20,1)
  2. 改為 range(5,101,5)
  3. 改為 range(0,100,5)
  4. 改為 range(5,100,5)
2. 解析(點擊後顯示)

逐一計算:

range(0,20,1)   → 0~19,共 20 次
range(5,101,5)  → 5~100,共 20 次
range(0,100,5)  → 0~95,共 20 次
range(5,100,5)  → 5~95,共 19 次

答案:D。

第 27 題

1. 題目

執行下列函式時,哪一行永遠不會被執行?

def F(a):
    while a < 10:
        a = a + 5

    if a < 12:
        a = a + 2

    if a < 11:
        a = 5
  1. a = a + 5
  2. a = a + 2
  3. a = 5
  4. 每一行都有可能執行
2. 解析(點擊後顯示)

while 結束時一定有 a >= 10

若此時 a 是 10 或 11,第二段 if 會再加 2,變成 12 或 13;若本來已經至少 12,則保持不變。

所以到最後一個 if 時,a 一定至少為 12,a < 11 永遠不成立。

答案:C,a = 5

第 28 題

1. 題目

下列函式執行後回傳的 x 為何?

def F(n):
    x = 0
    for i in range(1, n + 1):
        for j in range(i, n + 1):
            k = 1
            while k <= n:
                x = x + 1
                k = k * 2
    return x
  1. n(n+1)√⌊log₂n⌋
  2. n²(n+1)/2
  3. n(n+1)(⌊log₂n⌋+1)/2
  4. n(n+1)/2
2. 解析(點擊後顯示)

前兩層迴圈的總次數為:

n + (n-1) + ... + 1 = n(n+1)/2

內層 while 的 k1,2,4,8,...,因此執行:

⌊log₂n⌋ + 1

兩者相乘:

n(n+1)(⌊log₂n⌋+1)/2

答案:C。

第 29 題

1. 題目

下列程式想找出最大值 M 與最小值 N。哪一組初始列表可以測出程式有誤?

M, N, s = -1, 101, 3

for i in range(s):
    if A[i] > M:
        M = A[i]
    elif A[i] < N:
        N = A[i]
  1. [90,80,100]
  2. [80,90,100]
  3. [100,90,80]
  4. [90,100,80]
2. 解析(點擊後顯示)

錯誤原因是使用 elif:只要元素更新了最大值,就不會再檢查它是否也是目前最小值。

若列表嚴格遞增:

[80,90,100]

每個元素都會進入第一個 if,N 永遠維持 101,明顯錯誤。

答案:B。

第 30 題

1. 題目

下列程式輸出為何?

a = [0] * 101
b = [i for i in range(101)]

for i in range(1, 101):
    a[i] = b[i] + a[i - 1]

print(a[50] - a[30])
  1. 1275
  2. 20
  3. 1000
  4. 810
2. 解析(點擊後顯示)

a[i] 是 1 到 i 的前綴和:

a[50] = 1+2+...+50
a[30] = 1+2+...+30

兩者相減後,剩下 31 到 50:

31+32+...+50

共有 20 項,平均值是 (31+50)/2=40.5,所以總和為:

40.5 × 20 = 810

答案:D,810。