Companion to the AP-Style MC Practice SetAP 风格选择题练习的解析配套
Unit 2: Selection and Iteration第 2 单元:选择与循环CSA
Multiple Choice)—— 详细解析Each item restates the prompt and choices, marks the correct letter, and gives a brief justification. Trap distractors are called out where useful.每道题重述题干与选项、标出正确答案字母,并给出简明解析;对容易混淆的干扰项(trap distractor)单独提示。
x = 0; if (x != 0 && 10/x > 0) … → result?x = 0;if (x != 0 && 10/x > 0) … → 结果?
yes is printed.被打印。no is printed.被打印。ArithmeticException is thrown.抛出 ArithmeticException。&& short-circuits: if the left operand is false, the right operand is not evaluated.
x != 0 is false (since x = 0).&& is therefore false; 10 / x is never computed.else branch runs: no is printed.&& works. This "guard-then-use" idiom is the standard way to protect against division-by-zero and null dereference.
&& 是短路求值(short-circuit evaluation):如果左操作数为 false,右操作数根本不会被计算。
x != 0 为 false(因为 x = 0)。&& 直接为 false;10 / x 永远不会被求值。else 分支执行:打印 no。&& 并不是那样工作。这种"先保护、后使用"的写法是防止除以零和空引用解引用的标准技巧。
for (int i = 5; i <= 20; i += 3) — count iterations?for (int i = 5; i <= 20; i += 3) —— 循环了多少次?
56715i that satisfy i <= 20:
i = 5, 8, 11, 14, 17, 20 — six values23, which fails the test.⌊(end − start) / step⌋ + 1 when end is achievable. Here ⌊(20 − 5) / 3⌋ + 1 = 5 + 1 = 6. Trap (A) drops the inclusive endpoint; (C) over-counts by one (classic fencepost error).
i <= 20 的 i:
i = 5, 8, 11, 14, 17, 20 —— 六个值23,不再满足条件。end 恰好可达时,迭代次数 = ⌊(end − start) / step⌋ + 1。这里 ⌊(20 − 5) / 3⌋ + 1 = 5 + 1 = 6。陷阱 (A) 漏掉了能取到的右端点;(C) 多算了一次(典型的"栅栏柱错误" fencepost error)。
Equivalent to !(a < b || c >= d)?与 !(a < b || c >= d) 等价的是?
a > b && c < da >= b && c < da >= b || c < da > b || c < d!(P || Q) ≡ !P && !Q. Negate each clause carefully:
!(a < b) ≡ a >= b (the negation of "strictly less" is "greater or equal," not "strictly greater")!(c >= d) ≡ c < d&&: a >= b && c < d|| connective (forgot the second rule of De Morgan).
De Morgan's Law):!(P || Q) ≡ !P && !Q。逐个否定每个子条件:
!(a < b) ≡ a >= b("严格小于"的否定是"大于等于",不是"严格大于")!(c >= d) ≡ c < d&& 连接:a >= b && c < d|| 换成 &&(忘了德摩根的第二条规则)。
x = 15; nested if printing A/B/C, then D always.x = 15;嵌套 if 可能打印 A/B/C,之后总会打印 D。
ADBDBCDDx = 15:
x > 10 → true, enter outer if. The else if branch is now skipped entirely.x % 2 == 0 → 15 % 2 = 1, so false. The inner else runs: print B.ifs, println("D") runs: print D + newline.BD. Trap (C) assumes else if (x > 5) also fires — but only one branch in an if / else if chain ever runs.
x = 15 推演:
x > 10 → true,进入外层 if。else if 分支现在整段被跳过。x % 2 == 0 → 15 % 2 = 1,false。内层 else 执行:打印 B。if 后,println("D") 执行:打印 D 并换行。BD。陷阱 (C) 认为 else if (x > 5) 也会执行——但在 if / else if 链里,最多只会执行其中一个分支。
n = 234; while (n > 0) { s += n % 10; n /= 10; }n = 234;while (n > 0) { s += n % 10; n /= 10; }
69234432% 10 grabs the last digit, /= 10 chops it off.
234 % 10 = 4 → s = 4; n = 23.23 % 10 = 3 → s = 7; n = 2.2 % 10 = 2 → s = 9; n = 0.n > 0 fails. Exit. Print 9.% 10 取最低位,/= 10 把它去掉。
234 % 10 = 4 → s = 4;n = 23。23 % 10 = 3 → s = 7;n = 2。2 % 10 = 2 → s = 9;n = 0。n > 0 不再满足,退出。打印 9。s = "ProgrAmming"; count chars equal to 'a'/'e'/'i'/'o'/'u'.s = "ProgrAmming";统计等于 'a'/'e'/'i'/'o'/'u' 的字符个数。
1234chars with == is case-sensitive: 'A' == 'a' is false. Walk through the string:
P r o g r A m m i n g
0 1 2 3 4 5 6 7 8 9 10
Lower-case vowels only: o at 2, i at 8. Count = 2. The uppercase A at index 5 is not matched.
Trap (C) counts the uppercase A by treating the comparison as case-insensitive. To make this counter case-insensitive you'd normalize: Character.toLowerCase(c) == 'a' || …, or call s.toLowerCase() first.
== 比较 char 是区分大小写的(case-sensitive):'A' == 'a' 为 false。逐字符走一遍:
P r o g r A m m i n g
0 1 2 3 4 5 6 7 8 9 10
只匹配小写元音:o(下标 2)、i(下标 8)。计数 = 2。下标 5 处的大写 A 不会被匹配。
陷阱 (C) 把大写 A 也算上,相当于把比较当成了不区分大小写。要做成不区分大小写,可以先归一化:Character.toLowerCase(c) == 'a' || …,或先调 s.toLowerCase()。
n=100; count=0; stop=false; while (n>0 && !stop) { count++; if (count>5) stop=true; n-=10; } println(count + " " + n);n=100; count=0; stop=false; while (n>0 && !stop) { count++; if (count>5) stop=true; n-=10; } println(count + " " + n);
5 505 606 4010 0count increments first; n decrements last. The flag stop is set inside the body, but the loop condition only re-checks after the body completes. So the iteration where count first exceeds 5 still finishes — including the n -= 10.
iter | count after stop after n after
1 | 1 false 90
2 | 2 false 80
3 | 3 false 70
4 | 4 false 60
5 | 5 false 50
6 | 6 true 40 ← count>5 fires, stop set, n still drops
loop test now: 40>0 && !true = false → exit
Print: "6 40".
Trap (A) assumes stop=true short-circuits the rest of the body (it doesn't — if/then isn't break). (B) stops after the 5th decrement and before the count increment. (D) ignores the flag entirely.
count 先自增,n 最后再减。标志变量 stop 是在循环体内部被赋值的,但循环条件要等整个循环体执行完才重新检查。所以当 count 第一次超过 5 那一轮,整个循环体仍会跑完——包括 n -= 10。
iter | count after stop after n after
1 | 1 false 90
2 | 2 false 80
3 | 3 false 70
4 | 4 false 60
5 | 5 false 50
6 | 6 true 40 ← count>5 触发,stop 置真,但 n 仍然下降
loop test now: 40>0 && !true = false → 退出
打印:"6 40"。
陷阱 (A) 错以为 stop=true 会"短路"掉循环体后续语句(不会——if/then 不是 break)。(B) 在第 5 次减法之后、count 自增之前停止。(D) 完全忽略了标志变量。
for i = 1..4 { for j = 1..i { count++; } }for i = 1..4 { for j = 1..i { count++; } }
4101624i times for each outer i. Total iterations:
i = 1: inner runs 1 timei = 2: inner runs 2 timesi = 3: inner runs 3 timesi = 4: inner runs 4 times1 + 2 + 3 + 4 = 10. (This is the triangular number n(n+1)/2.)
Trap (C) assumes a full 4 × 4 rectangle (which would happen if the inner loop were j <= 4 independent of i). (A) counts only outer iterations.
i,内层循环跑 i 次。合计:
i = 1:内层跑 1 次i = 2:内层跑 2 次i = 3:内层跑 3 次i = 4:内层跑 4 次1 + 2 + 3 + 4 = 10。(这是三角数,n(n+1)/2。)
陷阱 (C) 把它当成完整的 4 × 4 矩形(如果内层是 j <= 4 与 i 无关,才会是 16)。(A) 只数了外层的次数。
n = 1234; while (n > 0) { rev = rev*10 + n%10; n /= 10; }n = 1234;while (n > 0) { rev = rev*10 + n%10; n /= 10; }
123443214324320rev = rev * 10 + (last digit of n) "shifts" the previously-accumulated digits left and appends the next digit. Trace:
n = 1234, rev = 0rev = 0·10 + 4 = 4; n = 123rev = 4·10 + 3 = 43; n = 12rev = 43·10 + 2 = 432; n = 1rev = 432·10 + 1 = 4321; n = 0 — exit.rev = 4321. Trap (C) stops one iteration early; (D) forgets the + n%10 on the last step.
rev = rev * 10 + (n 的最低位) 把已积累的数字"整体左移一位",然后把新的最低位接到末尾。逐轮推演:
n = 1234, rev = 0rev = 0·10 + 4 = 4;n = 123rev = 4·10 + 3 = 43;n = 12rev = 43·10 + 2 = 432;n = 1rev = 432·10 + 1 = 4321;n = 0 —— 退出。rev = 4321。陷阱 (C) 提前一轮停止;(D) 漏掉了最后一步的 + n%10。
a=5; b=3; while (a>0 || b>0) { if (a>0) a--; if (b>0) b--; } println(a + " " + b);a=5; b=3; while (a>0 || b>0) { if (a>0) a--; if (b>0) b--; } println(a + " " + b);
0 00 -22 0||, so the loop runs while either variable is still positive; (2) the inner if guards prevent b from going negative once it hits 0.
iter | a after b after loop test after
1 | 4 2 4>0 || 2>0 → true
2 | 3 1 true
3 | 2 0 true
4 | 1 0 (b guard skipped) true
5 | 0 0 0>0 || 0>0 → false → exit
Once b = 0, the if (b > 0) guard skips its decrement — so b stays at 0 while a finishes counting down.
Trap (B) drops the if (b>0) guard, so b goes negative (decrements once per iteration past 0). (C) swaps the roles. (D) assumes the loop can't terminate because of the OR — but eventually both reach 0 since each iteration strictly decreases the positive variable(s).
||,所以只要任何一个变量还为正,循环就继续;(2) 内部的 if 保护(guard)让 b 在到达 0 后不会变成负数。
iter | a after b after loop test after
1 | 4 2 4>0 || 2>0 → true
2 | 3 1 true
3 | 2 0 true
4 | 1 0 (b 的保护跳过自减) true
5 | 0 0 0>0 || 0>0 → false → 退出
一旦 b = 0,if (b > 0) 保护就会跳过它的自减——所以 b 停在 0,而 a 继续往下数。
陷阱 (B) 没有 if (b>0) 保护,b 会变负(每轮在 0 之后还减一次)。(C) 把两者的角色搞反了。(D) 以为 OR 让循环停不下来——其实只要正值变量每轮严格减少,最终都会到 0。
n = 0; p = 1; while (p < 1000) { p *= 2; n++; }n = 0; p = 1; while (p < 1000) { p *= 2; n++; }
91010001024iter | p after body n
1 | 2 1
2 | 4 2
3 | 8 3
4 | 16 4
5 | 32 5
6 | 64 6
7 | 128 7
8 | 256 8
9 | 512 9
10 | 1024 10
loop test: 1024 < 1000 false → exit
Note: the test p < 1000 uses the value of p before the next iteration. p = 512 is still < 1000, so the body runs once more — that final iteration is what pushes n from 9 to 10. Trap (A) stops at p = 512 without doing the final iteration; (D) reports p instead of n.
iter | p 执行后 n
1 | 2 1
2 | 4 2
3 | 8 3
4 | 16 4
5 | 32 5
6 | 64 6
7 | 128 7
8 | 256 8
9 | 512 9
10 | 1024 10
loop test: 1024 < 1000 false → 退出
注意:循环条件 p < 1000 用的是下一次循环开始之前的 p。p = 512 仍然 < 1000,所以循环体还要再跑一次——正是这最后一次把 n 从 9 推到 10。陷阱 (A) 在 p = 512 处停下,没做最后那一轮;(D) 报的是 p 的值而不是 n。
n=100; count=0; for (int i=n; i>1; i=i/2) count++; println(count);n=100; count=0; for (int i=n; i>1; i=i/2) count++; println(count);
56750i = i / 2 is integer division, so values shrink fast and round down. The condition is i > 1 (not > 0), so the loop exits once i reaches 1.
iter | i before i after = i/2 count after
1 | 100 50 1
2 | 50 25 2
3 | 25 12 3
4 | 12 6 4
5 | 6 3 5
6 | 3 1 6
loop test: 1 > 1 false → exit
So count = 6 — equivalently, ⌊log₂(100)⌋ = 6 (since 2⁶ = 64 ≤ 100 < 128 = 2⁷).
Trap (A) stops when i reaches 2 (off-by-one on the loop bound). (C) counts the would-be iteration at i = 1. (D) mistakes the loop for one that runs n/2 times.
i = i / 2 是整除,所以值缩小很快、还会向下取整。退出条件是 i > 1(不是 > 0),所以 i 到 1 就退出。
iter | i 执行前 i 执行后 = i/2 count 执行后
1 | 100 50 1
2 | 50 25 2
3 | 25 12 3
4 | 12 6 4
5 | 6 3 5
6 | 3 1 6
loop test: 1 > 1 false → 退出
所以 count = 6 —— 等价于 ⌊log₂(100)⌋ = 6(因为 2⁶ = 64 ≤ 100 < 128 = 2⁷)。
陷阱 (A) 在 i 到 2 时就停(循环边界算错了一)。(C) 多算了 i = 1 时那一轮。(D) 把循环误当作要跑 n/2 次。
x=7; result=""; if(x>0) result+="P"; if(x%2==0) result+="E"; else if(x>5) result+="B"; if(x<10 && x>3) result+="M"; println(result);x=7; result=""; if(x>0) result+="P"; if(x%2==0) result+="E"; else if(x>5) result+="B"; if(x<10 && x>3) result+="M"; println(result);
PBMPEBMPEBPMif statements — but the second one has an attached else if. That changes its behavior: the chain runs at most one of its branches; the independent ifs each run on their own merits.
if (independent): x > 0 → 7 > 0 true → append "P". Result: "P".if/else if (chain): x % 2 == 0 → 7 % 2 = 1 false → check else if (x > 5) → true → append "B". The "E" branch is skipped and so is any sibling once one branch fires. Result: "PB".if (independent): x < 10 && x > 3 → both true → append "M". Result: "PBM"."PBM".
Trap (B) "PEBM" treats the chain as two independent ifs (both E and B branches appended). (C) ignores the final independent if. (D) sees the chain correctly but skips both its branches (forgetting else if).
if 语句——但第二条带了一个 else if。这就改变了它的行为:链式结构里最多只执行一个分支;独立的 if 各自按条件独立判断。
if(独立):x > 0 → 7 > 0 true → 追加 "P"。结果:"P"。if/else if(链式):x % 2 == 0 → 7 % 2 = 1 false → 检查 else if (x > 5) → true → 追加 "B"。"E" 分支被跳过——同一个链里一旦有分支命中,剩下的分支都不会运行。结果:"PB"。if(独立):x < 10 && x > 3 → 两个都为 true → 追加 "M"。结果:"PBM"。"PBM"。
陷阱 (B) "PEBM" 把链式当作两个独立 if(E 和 B 两个分支都追加)。(C) 忽略了最后那条独立 if。(D) 链式判断正确但跳过了两个分支(忘了 else if)。
total=0; for(i=1..6) for(j=i..6) if((i+j)%3==0) total++; println(total);total=0; for(i=1..6) for(j=i..6) if((i+j)%3==0) total++; println(total);
67812j = i (not 1), so we only count unordered pairs (i, j) with i ≤ j ≤ 6 where i + j is divisible by 3. Walk row by row:
i=1, j∈{1..6}: hits at j=2 (sum 3), j=5 (sum 6) → 2
i=2, j∈{2..6}: hits at j=4 (sum 6) → 1
i=3, j∈{3..6}: hits at j=3 (sum 6), j=6 (sum 9) → 2
i=4, j∈{4..6}: hits at j=5 (sum 9) → 1
i=5, j∈{5..6}: no hits (sums 10, 11) → 0
i=6, j=6: hits at j=6 (sum 12) → 1
total = 2+1+2+1+0+1 = 7
Print: 7.
Trap (D) 12 counts the full 6×6 grid's hits (would be right if inner ran j = 1..6 — double-counts unordered pairs and includes ordered duplicates). (A) 6 miscounts a row. (C) 8 double-counts a single pair.
j = i 而不是 1 开始,所以只数无序对 (i, j)(满足 i ≤ j ≤ 6)且 i + j 能被 3 整除的情况。逐行扫描:
i=1, j∈{1..6}: 命中 j=2(和 3)、j=5(和 6) → 2
i=2, j∈{2..6}: 命中 j=4(和 6) → 1
i=3, j∈{3..6}: 命中 j=3(和 6)、j=6(和 9) → 2
i=4, j∈{4..6}: 命中 j=5(和 9) → 1
i=5, j∈{5..6}: 没有命中(和为 10、11) → 0
i=6, j=6: 命中 j=6(和 12) → 1
total = 2+1+2+1+0+1 = 7
打印:7。
陷阱 (D) 12 是把整个 6×6 网格的命中都数上(相当于内层跑 j = 1..6——把无序对重复计数)。(A) 6 某一行数错了。(C) 8 多算了一对。
n=13; count=0; while(n>1) { if(n%2==0) n/=2; else n--; count++; } println(count);n=13; count=0; while(n>1) { if(n%2==0) n/=2; else n--; count++; } println(count);
45612n (when even) or subtracts 1 (when odd). count tracks every iteration, not just halvings. Trace from n = 13:
iter | n before branch n after count after
1 | 13 else 12 1 (odd: decrement)
2 | 12 if 6 2 (even: halve)
3 | 6 if 3 3 (even: halve)
4 | 3 else 2 4 (odd: decrement)
5 | 2 if 1 5 (even: halve)
loop test: 1 > 1 false → exit
Print: 5.
Trap (A) 4 miscounts by 1 — usually skipping the first "odd → 12" iteration. (C) 6 runs one extra loop (forgets the exit is at n = 1, not 0). (D) 12 counts the value of n after one decrement instead of count.
n 减半(偶数时),要么减 1(奇数时)。count 记录的是每一轮的次数,而不仅仅是减半的次数。从 n = 13 推演:
iter | n 执行前 分支 n 执行后 count 执行后
1 | 13 else 12 1 (奇数:减 1)
2 | 12 if 6 2 (偶数:减半)
3 | 6 if 3 3 (偶数:减半)
4 | 3 else 2 4 (奇数:减 1)
5 | 2 if 1 5 (偶数:减半)
loop test: 1 > 1 false → 退出
打印:5。
陷阱 (A) 4 数错了一次——通常是漏掉第一轮"奇数 → 12"。(C) 6 多跑了一轮(忘了退出条件是 n = 1,不是 0)。(D) 12 把一次减 1 后的 n 当作了答案,没看 count。