108 高普考普通考試 資訊處理 程式設計概要 考古題詳解
第 一 題25 分
Java 程式 PreStars 會印出什麼結果?維持巢狀 for 迴圈架構,小修 PreStars,讓它印出以下的星星構圖。
public class PreStars { public static void main(String[] args) { for (int i=1; i<=5; i++) { for (int j=1; j<=i; j++) System.out.print('*'); System.out.println(); } } }
應印出:
******
*****
****
***
**
*
登入後即可作答並保存紀錄。
核心觀念
本題評量巢狀迴圈(Nested Loops)的執行流程控制與圖形輸出規律建模能力,為國考資訊處理類科《程式設計概要》的經典基本題型。核心觀念包含:
- 巢狀迴圈的控制分工:
- 外層迴圈(Outer Loop):負責控制輸出的「列數(Rows)」與換行時機。
- 內層迴圈(Inner Loop):負責控制該列中各「行(Columns)」所輸出的字元內容與次數。
- 輸出函數的差異:
System.out.print:輸出字元後不換行,用於在同一列連續輸出空白或星號。System.out.println:輸出換行字元(移至下一列開頭)。
- 線性關係規律推導:
- 圖形輸出題必須將幾何構圖轉換為代數關係式。設外層列指標為 ,推導出該列所需「空白字元數」與「星號字元數」關於 的一次方程式(等差數列)。
解題方法
第一部分:分析原程式 PreStars 的輸出結果
原程式結構如下:
for (int i=1; i<=5; i++) {
for (int j=1; j<=i; j++)
System.out.print('*');
System.out.println;
}
追蹤外層與內層迴圈變數的迭代過程:
- 外層迴圈 從 遞增至 ,共執行 次,代表輸出 列。
- 當 :內層 範圍為 ,執行 次,印出
*,接著換行。 - 當 :內層 範圍為 ,執行 次,印出
**,接著換行。 - 當 :內層 範圍為 ,執行 次,印出
***,接著換行。 - 當 :內層 範圍為 ,執行 次,印出
****,接著換行。 - 當 :內層 範圍為 ,執行 次,印出
*****,接著換行。
因此,原程式會輸出一個高度為 列、靠左對齊的直角三角形星號圖形。
第二部分:修改程式以輸出目標星號構圖
步驟一:分析目標圖形的數學規律
題目要求的構圖共有 列,每列由前導空白(Space)與星號(*)組成。
以列指標 (令 從 到 )建立對應關係表:
| 列號 | 前導空白數 | 星號數 | 規律推導 |
|---|---|---|---|
| 空白 ;星號 | |||
| 空白 ;星號 | |||
| 空白 ;星號 | |||
| 空白 ;星號 |
通式驗算:
- 前導空白數為公差為 的等差數列:首項為 ,故第 列的空白數為 。
- 星號數為公差為 的等差數列:首項為 ,故第 列的星號數為 。
步驟二:程式修改架構設計
維持題目要求的「巢狀 for 迴圈架構」與「小修」原則,評分實務上採納以下兩種標準作法:
- 解法 A(經典雙內層迴圈法): 外層迴圈維持 控制列數(範圍改為 到 )。
第 二 題25 分
下列為 Reverse class 的程式規範與其執行結果,試以遞迴(recursive)的方式完成副程式 reverse(int[] arr, int x)。撰寫時,必須使用相同的參數名稱與資料型態。
reverse(int[] arr, int x) 會回傳一個倒過來擺置的整數串:arr[n-1]、arr[n-2]、……、arr[x+1]、arr[x],假設 arr 內共有 個元素,而且 。
public class Reverse { public static String reverse(int[] arr, int x) {
}
public static void main(String[] args)
{
int[] intArr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
String results = reverse(intArr, 2);
System.out.println(results);
System.out.println(reverse(intArr, 7));
}
}
執行結果:
10 9 8 7 6 5 4 3 10 9 8
登入後即可作答並保存紀錄。
核心觀念
本題評量遞迴副程式(Recursive Subroutine)的設計能力與字串處理技巧,重點概念包含:
- 遞迴三要素:
- 基底條件(Base Case / 終止條件):停止遞迴並直接回傳結果的邊界,避免無窮遞迴導致堆疊溢位(
StackOverflowError)。 - 遞迴步驟(Recursive Step):將原問題拆解為結構相同但規模較小的子問題。
- 向終止條件逼近:每次遞迴呼叫時,傳入的狀態必須往基底條件推進。
- 呼叫堆疊(Call Stack)與回溯特性(Backtracking):
題目要求輸出反向整數串(從索引 倒數輸出至 )。在副程式參數固定為
(int[] arr, int x)且不可增減參數的限制下,必須利用呼叫堆疊的「後進先出(LIFO)」特性:先遞迴深入至陣列尾端( 逐次加 1 逼近 ),於回溯階段(Return)才將當前元素 串接在後方。
解題方法
1. 題意與子問題分析
給定陣列長度為 (即 arr.length),需回傳的整數串為:
觀察子問題的關係:
- 若已取得
reverse(arr, x + 1)的結果:。 - 則
reverse(arr, x)的完整字串即為:reverse(arr, x + 1) + " " + arr[x]。
2. 基底條件(Base Case)設計
- 極限邊界:題目指出 。若 (即 ),表示不包含任何元素,應回傳空字串
""。 - 最後一個元素:當 (即
arr.length - 1)時,為倒序字串的第一個輸出元素(即 )。此時直接將該整數轉為字串回傳,不需前置空格,作為遞迴終止的基準點。
3. 追蹤驗算(Trace)
以 reverse(intArr, 7) 為例(其中 intArr 長度 ):
- 呼叫
reverse(arr, 7):等待reverse(arr, 8)的結果。 - 呼叫
reverse(arr, 8):等待reverse(arr, 9)的結果。 - 呼叫
reverse(arr, 9):符合 ,直接回傳字串"10"。 - 回溯至第 2 步:回傳
"10" + " " + arr[8]"10 9"。 - 回溯至第 1 步:回傳
"10 9" + " " + arr[7]"10 9 8"。
輸出結果與題目範例完全吻合,且開頭與尾端均無多餘空格。
選項分析
第 三 題15 分
下列 Python 程式的執行結果為何?
list = [2,2,3,7,7,7,9,9,10,10] count = 1 current = list[0]
for i in list: if i > current: list[count] = i count += 1 current = i
last = len(list)
if last > count: for i in range(count, last): list.pop()
print("count = ", count) print("list = ", list)
登入後即可作答並保存紀錄。
核心觀念
本題為經典的已排序串列原地去重複演算法(In-place Remove Duplicates from Sorted Array),核心測驗考生對以下四項觀念的理解:
- 雙指標(快慢指標)機制:利用快指標(
for迴圈中的 )循序走訪串列,慢指標(變數count)記錄不重複元素的個數,同時標記下一個新相異元素應覆寫的索引位置。 - 條件覆寫(In-place Modification):若快指標數值大於當前記錄的最大相異值(),則將該值寫入慢指標位置
list[count],並推進慢指標()。 - 區間迭代與尾端刪除:
range(count, last)產生半開區間 的整數序列,透過list.pop逐次自串列末端移除元素,將多餘的舊元素截除。 - Python
print函式之預設引數:print傳入多個引數時,預設會以單一空白字元(sep=' ')作為引數間的分隔符號。
解題方法
解題切入點採用程式分段追蹤法,將程式碼拆解為三個主要階段進行推導:
階段一:變數初始化
- 初始串列:
list = [2, 2, 3, 7, 7, 7, 9, 9, 10, 10],長度為 10。 count = 1:代表已保留第 0 個元素,去重複後的有效長度從 1 開始計數。current = list[0] = 2:記錄目前最新的相異值基準。
階段二:for 迴圈走訪與覆寫
迴圈依序取出 list 中的元素 ,當 時觸發覆寫與累加:
| 迭代次數 | 元素 | 判斷式 | 執行動作 | count | current | list 當前內容 |
|---|---|---|---|---|---|---|
| 1 | 2 | (False) | 不執行 | 1 | 2 | [2, 2, 3, 7, 7, 7, 9, 9, 10, 10] |
| 2 | 2 | (False) | 不執行 | 1 | 2 | [2, 2, 3, 7, 7, 7, 9, 9, 10, 10] |
| 3 | 3 | (True) | list[1] = 3 | 2 | 3 | [2, 3, 3, 7, 7, 7, 9, 9, 10, 10] |
| 4 | 7 | (True) | list[2] = 7 | 3 | 7 | [2, 3, 7, 7, 7, 7, 9, 9, 10, 10] |
| 5 | 7 | (False) | 不執行 | 3 | 7 | [2, 3, 7, 7, 7, 7, 9, 9, 10, 10] |
| 6 | 7 | (False) | 不執行 | 3 | 7 | [2, 3, 7, 7, 7, 7, 9, 9, 10, 10] |
| 7 | 9 | (True) | list[3] = 9 | 4 | 9 | [2, 3, 7, 9, 7, 7, 9, 9, 10, 10] |
| 8 | 9 | (False) | 不執行 | 4 | 9 | [2, 3, 7, 9, 7, 7, 9, 9, 10, 10] |
| 9 | 10 | (True) | list[4] = 10 | 5 | 10 | [2, 3, 7, 9, 10, 7, 9, 9, 10, 10] |
第 四 題35 分
數學中複數是實數的延伸,複數通常表示為 或 ,其中 為實數,分別稱為複數的實部與虛部, 為虛數單位,且 。複數的加、減、乘、除運算定義如下:
試參考以下程式回答問題:
public class Complex { private double real; private double imaginary;
public Complex()
{
this(0.0, 0.0);
}
public Complex(double r, double i)
{
real = r;
imaginary = i;
}
public Complex add(Complex right)
{
return new Complex(real + right.real,
imaginary + right.imaginary);
}
public Complex subtract(Complex right)
{
return new Complex(real - right.real,
imaginary - right.imaginary);
}
public String toString()
{
return String.format("(%.1f, %.1f)", real, imaginary);
}
} // end class Complex
public class ComplexTest { public static void main(String[] args) { Complex x = new Complex(1, 1); Complex y = new Complex(2, 2);
System.out.printf("x = %s%n", x.toString());
System.out.printf("y = %s%n", y);
}
} // end class ComplexTest
(一)此程式的列印結果為何?
(二)利用 add(),在 ComplexTest.java 中加入一行程式,以印出「x + y = (3.0, 3.0)」。
(三)於 Complex.java 中撰寫:
public Complex division(Complex right)
回傳資料型態與參數命名必須分別為 Complex 與 right。
(四)利用 division(),在 ComplexTest.java 中算出 的倒數(如果 ,則稱 為 的倒數),並列印出有意義的訊息。
(五)撰寫 public String standardForm(),以印出複數的另一表示法 。注意:
要表示為 ;
要表示為 ;
要表示為 。
登入後即可作答並保存紀錄。
核心觀念
本題為典型的「物件導向程式設計(OOP)」實作題,重點測驗 Java 類別的封裝、物件狀態操作與數學模型對應能力:
- 物件封裝與成員存取權限:類別內部的
private成員變數(real與imaginary),在同一個類別的不同物件實例(Instance)之間具備存取權限。例如在add(Complex right)或division(Complex right)中,可直接存取right.real。 toString覆寫與輸出機制:Java 中任何物件傳入System.out.printf("%s")或System.out.print時,皆會自動呼叫該物件的toString方法。- 複數除法與倒數的代數定義:
- 複數除法:
- 倒數定義:若 ,則 。
- 字串格式化與邊界條件判斷:輸出特殊代數格式時,需根據實部與虛部的數值狀態(、、正負號)進行條件分支處理。
解題方法與逐步推導
(一)列印結果分析
- 程式建立兩個複數物件:
x的實部為1.0、虛部為1.0。y的實部為2.0、虛部為2.0。
Complex類別覆寫了toString,其格式化字串為String.format("(%.1f, %.1f)", real, imaginary),保留小數點後一位。- 第一行輸出:
System.out.printf("x = %s%n", x.toString);
- 明確呼叫
x.toString,回傳"(1.0, 1.0)"。 - 印出:
x = (1.0, 1.0)並換行。
- 第二行輸出:
System.out.printf("y = %s%n", y);
%s轉換符會自動呼叫y.toString,回傳"(2.0, 2.0)"。- 印出:
y = (2.0, 2.0)並換行。
(二)利用 add 列印相加結果
x.add(y)會以x為主體,將y作為引數傳入,計算 ,回傳一個新的Complex(3.0, 3.0)物件。- 題目要求印出
x + y = (3.0, 3.0),配合ComplexTest.java原有的printf風格,直接將x.add(y)置入輸出敘述中:
System.out.printf("x + y = %s%n", x.add(y));
(亦可使用 System.out.println("x + y = " + x.add(y));)
(三)撰寫 division(Complex right)
- 方法簽章:依題意必須為
public Complex division(Complex right)。 - 數學公式與程式變數對應:
- 被除數(
this):,。 - 除數(
right):,。 - 分母:。
- 新實部:。
- 新虛部:。
- 回傳值:透過建構子回傳包含計算後之實部與虛部的新
Complex物件。
(四)利用 division 計算 的倒數
- 倒數之代數轉換:
- 實數 的複數表示為 ,即
new Complex(1.0, 0.0)。 - 的倒數 ,即以複數 呼叫
division(y)。
- 程式實作:
- 宣告代表 的複數物件,或直接鏈式呼叫:
new Complex(1.0, 0.0).division(y)。 - 將結果輸出為有意義之說明文字(包含計算結果)。
- 代數驗算:
經
toString的%.1f格式化後輸出為(0.3, -0.3)。