APCS Python 程式識讀 30 題
每題分為「1. 題目」與「2. 解析」。題目區沒有答案標色;解析預設收合,作答後再點開。
建議先用紙筆追蹤變數、迴圈次數與遞迴呼叫,再查看解析。
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
- 3840
- -3840
- 執行時導致無窮迴圈,不會停止執行
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。
1. 題目
給定下列程式,若輸出結果為 [1][2][3][5][4][6],程式中的 (?) 應為何?
for i in range(5):
j = 0
while (?):
print(f'[{i + j}]', end='')
j = j + 2
j < ij > ij <= ij >= i
2. 解析(點擊後顯示)
逐一代入 i=0,1,2,3,4,並觀察 j 從 0 開始,每次增加 2。
| i | 可執行的 j | 印出 i+j |
|---|---|---|
| 0 | 無 | 無 |
| 1 | 0 | 1 |
| 2 | 0 | 2 |
| 3 | 0、2 | 3、5 |
| 4 | 0、2 | 4、6 |
這正好對應條件 j < i。
答案:A,j < i。
1. 題目
給定下列函式,已知 f(14)、f(10)、f(6) 分別回傳 25、18、10,空格應填何者?
def f(n):
if n < 2:
return n
else:
return n + f(?)
(n + 1) // 2n // 2(n - 1) // 2(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。
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])
- 9
- 18
- 27
- 30
2. 解析(點擊後顯示)
程式每取出三個數時,只把第三個放回佇列尾端,前兩個永久刪除。
第一輪處理 1 到 30 後,留下:
3, 6, 9, 12, 15, 18, 21, 24, 27, 30
接著必須延續原本的 count 狀態繼續模擬,不能把計數器重新開始。持續處理後,最後剩下的元素是 18。
答案:B,18。
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
- 2
- 3
- 4
2. 解析(點擊後顯示)
空白數量原本是 4,3,2,1,0,已經正確。
星號目前是 1,2,3,4,5,但需要的是 1,3,5,7,9,每次應增加 2。
m = m + 2
只需修改第 7 行。
答案:A,修改 1 行。
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
n1=33, n2=4n1=33, n2=5n1=34, n2=4n1=34, n2=5
2. 解析(點擊後顯示)
先找出 100 的索引:
3k + 1 = 100
k = 33
線性搜尋從索引 0 檢查到索引 33,包含兩端,因此是 34 次。
二分搜尋的中點依序為:
49 → 24 → 36 → 30 → 33
共 5 次找到。
答案:D,n1=34, n2=5。
1. 題目
以下程式用來計算第 N 個費氏數列值,空格 (a)、(b) 應填何者?
a = 0
b = 1
for i in range(2, N + 1):
temp = b
(a)
a = temp
print((b))
(a) f[i]=f[i-1]+f[i-2] (b) f[N](a) a=a+b (b) a(a) b=a+b (b) a(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。
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)
- 印出的數字最大的是 4
f1一共被呼叫二次f2一共被呼叫三次- 數字 2 被印出兩次
2. 解析(點擊後顯示)
呼叫結構如下:
f1(1)
└─ f2(3)
└─ f1(2)
└─ f2(4)
輸出順序為:
1 3 2 4 2 3 1
f1 被呼叫 2 次,f2 也只被呼叫 2 次。
答案:C。
1. 題目
下列程式欲求 76 與 48 的最大公因數,while 內容何者正確?
i = 76
j = 48
while (i % j) != 0:
____________
____________
____________
print(j)
k = i % j i = j j = ki = j j = k k = i % ji = j j = i % k k = ik = 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。
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)
- 11
- 13
- 15
- 16
2. 解析(點擊後顯示)
第一個 if 使 count=11。第二個 if 成立,再使它變成 12。
12 % 3 = 0,不等於 4,因此內層 else 把 count 設成 0。
Python 中整數 0 是 Falsy(假值),所以最後執行外層 else,得到 16。
答案:D,16。
1. 題目
下列函式欲計算 n!,應如何修改才會得到正確結果?
1. def fun(n):
2. fac = 1
3. if n >= 0:
4. fac = n * fun(n - 1)
5. return fac
- 第 2 行改為
fac = n - 第 3 行改為
if n > 0: - 第 4 行改為
fac = n * fun(n + 1) - 第 4 行改為
fac = fac * fun(n - 1)
2. 解析(點擊後顯示)
階乘的基底條件應為 0! = 1。
原程式在 n=0 時仍會遞迴到 -1、-2...,無法停止。將條件改為 n > 0,當 n=0 時會直接回傳初始值 1。
答案:B。
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, 2, 10, 1, 20, 2, 11, 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)。
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
- 6
- 11
- 13
- 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。
1. 題目
下列函式的 else 部分應填何者,才能使 Mystery(9) 回傳 34?
def Mystery(x):
if x <= 1:
return x
else:
return ____________
x + Mystery(x - 1)x * Mystery(x - 1)Mystery(x - 2) + Mystery(x + 2)Mystery(x - 2) + Mystery(x - 1)
2. 解析(點擊後顯示)
基底為 Mystery(0)=0、Mystery(1)=1。若每項等於前兩項相加,就得到:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34
因此第 9 項為 34。
答案:D。
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=' ')
2 4 6 8 9 7 5 3 1 91 3 5 7 9 2 4 6 8 91 2 3 4 5 6 7 8 9 92 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。
1. 題目
下列函式以 F(7) 呼叫後回傳 12,則條件應為何?
def F(a):
if <condition>:
return 1
else:
return F(a - 2) + F(a - 3)
a < 3a < 2a < 1a < 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。
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')
- 20
- 11
- 2
- 10
2. 解析(點擊後顯示)
s > 70 的條件放在 s > 60 後面,因此 71~79 會先被判成 D;70 也會因為 70 > 60 被判成 D。
也就是 70~79 共 10 個分數錯誤。
另外 60 不滿足 s > 60,最後被判為 F,又多 1 個錯誤。
答案:B,共 11 個。
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
- 36
- 20
- 12
- 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。
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('')
- 2
- 1
- 0
- -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。
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
- 冗餘程式碼在 A 區
- 冗餘程式碼在 B 區
- 冗餘程式碼在 C 區
- 冗餘程式碼在 D 區
2. 解析(點擊後顯示)
任何整數除以 1 的餘數都為 0:
Change % 1 == 0
最後一行把 Change 設為 0,但程式後面已不再使用它,因此不影響輸出或功能。
答案:D。
1. 題目
執行 G(3,7) 後回傳值為何?
def G(a, x):
if x == 0:
return 1
else:
return a * G(a, x - 1)
- 128
- 2187
- 6561
- 1024
2. 解析(點擊後顯示)
每層遞迴都乘上一個 a,直到 x=0 回傳 1,因此:
G(a,x) = a^x
G(3,7)=3^7=2187。
答案:B,2187。
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]
Search(-1)Search(0)Search(10)Search(16)
2. 解析(點擊後顯示)
前三個呼叫都有合法答案:
Search(-1) → 0
Search(0) → 2
Search(10) → 12
但列表中沒有任何值大於 16。程式仍會回傳最後一個元素 14,這不符合函式目的。
答案:D,Search(16)。
1. 題目
下列函式的兩個 return 應分別填何者,才能正確計算最大公因數?
def GCD(a, b):
r = a % b
if r == 0:
return ______
return ______
a, GCD(b,r)b, GCD(b,r)a, GCD(a,r)b, GCD(a,r)
2. 解析(點擊後顯示)
若 a % b == 0,代表 b 能整除 a,最大公因數就是 b。
否則利用:
gcd(a,b) = gcd(b, a%b)
下一層應呼叫 GCD(b,r)。
答案:B。
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]
p是列表最大值q是列表最小值q < pA[0] <= p
2. 解析(點擊後顯示)
若所有元素都相同,例如:
A = [5,5,5]
則最大值和最小值都為 5,所以只能保證 q <= p,不能保證嚴格小於。
答案:C。
1. 題目
依序輸入 0~9 後,列表 X 的元素依序為何?
def F():
X = [0] * 10
for i in range(10):
X[(i + 2) % 10] = int(input())
0,1,2,3,4,5,6,7,8,92,0,2,0,2,0,2,0,2,09,0,1,2,3,4,5,6,7,88,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。
1. 題目
原程式無法正確列印 20 次 Hi!。下列哪個修改仍無法列印 20 次?
for i in range(0, 101, 5):
print('Hi!')
- 改為
range(0,20,1) - 改為
range(5,101,5) - 改為
range(0,100,5) - 改為
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。
1. 題目
執行下列函式時,哪一行永遠不會被執行?
def F(a):
while a < 10:
a = a + 5
if a < 12:
a = a + 2
if a < 11:
a = 5
a = a + 5a = a + 2a = 5- 每一行都有可能執行
2. 解析(點擊後顯示)
while 結束時一定有 a >= 10。
若此時 a 是 10 或 11,第二段 if 會再加 2,變成 12 或 13;若本來已經至少 12,則保持不變。
所以到最後一個 if 時,a 一定至少為 12,a < 11 永遠不成立。
答案:C,a = 5。
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
n(n+1)√⌊log₂n⌋n²(n+1)/2n(n+1)(⌊log₂n⌋+1)/2n(n+1)/2
2. 解析(點擊後顯示)
前兩層迴圈的總次數為:
n + (n-1) + ... + 1 = n(n+1)/2
內層 while 的 k 為 1,2,4,8,...,因此執行:
⌊log₂n⌋ + 1
兩者相乘:
n(n+1)(⌊log₂n⌋+1)/2
答案:C。
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]
[90,80,100][80,90,100][100,90,80][90,100,80]
2. 解析(點擊後顯示)
錯誤原因是使用 elif:只要元素更新了最大值,就不會再檢查它是否也是目前最小值。
若列表嚴格遞增:
[80,90,100]
每個元素都會進入第一個 if,N 永遠維持 101,明顯錯誤。
答案:B。
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])
- 1275
- 20
- 1000
- 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。