AP · thinka 原创模拟试题

2023 AP AP Computer Science A 模拟试题及答案详解

Thinka May 2023 AP-Style Mock — AP Computer Science A

36 90 分钟2023
An original Thinka practice paper modelled on the structure and difficulty of the May 2023 AP AP Computer Science A paper. Not affiliated with or reproduced from AP.

部分 II: Free Response

Answer all four questions. All code segments must be written in Java. Assume classes in the Java Quick Reference are imported.
4 题目 · 36
题目 1 · Free Response
9
This question involves the `ServerCluster` class, which manages compute tasks across worker nodes in a data center. Tasks can be scheduled on one of several worker nodes, numbered $1$ through $10$. Each node operates over a 24-hour daily cycle, divided into $24$ one-hour time slots numbered $0$ through $23$.

A requested computing task has a duration, which is the number of consecutive hours the task requires. In order for a task to be scheduled on a given node, the node must have a block of consecutive available hours that is at least equal to the requested duration. Scheduled tasks must start and end on the same worker node within the 24-hour cycle (hours $0$ through $23$).

The `ServerCluster` class contains two helper methods: `isNodeAvailable` and `reserveNode`. You will write two additional methods of the `ServerCluster` class.

```java
public class ServerCluster
{
/**
* Returns true if worker node nodeNum is available for task execution
* during hour; returns false otherwise.
* Preconditions: 1 <= nodeNum <= 10; 0 <= hour <= 23
/
private boolean isNodeAvailable(int nodeNum, int hour)
{ /
implementation not shown */ }

/**
* Marks the block of hours on nodeNum that begins at startHour and
* lasts for duration hours as reserved.
* Preconditions: 1 <= nodeNum <= 10; 0 <= startHour <= 23;
* 1 <= duration <= 24;
* startHour + duration <= 24
/
private void reserveNode(int nodeNum, int startHour, int duration)
{ /
implementation not shown */ }

/**
* Searches nodeNum for the first block of duration consecutive available
* hours during the day (hours 0 to 23), as described in part (a).
* Returns the starting hour of the block if found, or -1 if no such
* block is found.
* Preconditions: 1 <= nodeNum <= 10; 1 <= duration <= 24
/
public int findContinuousBlock(int nodeNum, int duration)
{ /
to be implemented in part (a) */ }

/**
* Searches worker nodes from startNode to endNode, inclusive, for a block
* of duration consecutive available hours, as described in part (b).
* If such a block is found, calls reserveNode to reserve the block and
* returns true; otherwise, returns false.
* Preconditions: 1 <= startNode <= endNode <= 10; 1 <= duration <= 24
/
public boolean scheduleTask(int startNode, int endNode, int duration)
{ /
to be implemented in part (b) */ }

// There may be instance variables, constructors, and methods that are not shown.
}
```

(a) Write the `findContinuousBlock` method, which searches `nodeNum` for the first block of available hours that is `duration` hours long. If such a block is found, `findContinuousBlock` returns the starting hour of the block. Otherwise, `findContinuousBlock` returns `-1`. The `findContinuousBlock` method uses the helper method `isNodeAvailable`, which returns `true` if the node is available at a given hour and `false` otherwise. No hours should be marked as reserved as a result of calling `findContinuousBlock`.

Complete the `findContinuousBlock` method:
```java
/**
* Searches nodeNum for the first block of duration consecutive available
* hours during the day (hours 0 to 23), as described in part (a).
* Returns the starting hour of the block if found, or -1 if no such
* block is found.
* Preconditions: 1 <= nodeNum <= 10; 1 <= duration <= 24
*/
public int findContinuousBlock(int nodeNum, int duration)
```

(b) Write the `scheduleTask` method, which searches worker nodes from `startNode` to `endNode`, inclusive, for the earliest available block of `duration` consecutive hours on the lowest-numbered node. If such a block is found, `scheduleTask` calls `reserveNode` to reserve the block on that node and returns `true`. If no such block is found on any of the specified nodes, `scheduleTask` returns `false`.

Assume that `findContinuousBlock` works as intended, regardless of what you wrote in part (a). You must use `findContinuousBlock` and `reserveNode` appropriately in order to receive full credit.

Complete the `scheduleTask` method:
```java
/**
* Searches worker nodes from startNode to endNode, inclusive, for a block
* of duration consecutive available hours, as described in part (b).
* If such a block is found, calls reserveNode to reserve the block and
* returns true; otherwise, returns false.
* Preconditions: 1 <= startNode <= endNode <= 10; 1 <= duration <= 24
*/
public boolean scheduleTask(int startNode, int endNode, int duration)
```
查看答案详解

解题

### Part (a) Implementation

```java
public int findContinuousBlock(int nodeNum, int duration)
{
int consecutive = 0;
for (int hour = 0; hour < 24; hour++)
{
if (isNodeAvailable(nodeNum, hour))
{
consecutive++;
if (consecutive == duration)
{
return hour - duration + 1;
}
}
else
{
consecutive = 0;
}
}
return -1;
}
```

Alternative Solution for Part (a):
```java
public int findContinuousBlock(int nodeNum, int duration)
{
for (int startHour = 0; startHour <= 24 - duration; startHour++)
{
boolean isAvailable = true;
for (int h = 0; h < duration; h++)
{
if (!isNodeAvailable(nodeNum, startHour + h))
{
isAvailable = false;
}
}
if (isAvailable)
{
return startHour;
}
}
return -1;
}
```

---

### Part (b) Implementation

```java
public boolean scheduleTask(int startNode, int endNode, int duration)
{
for (int node = startNode; node <= endNode; node++)
{
int startHour = findContinuousBlock(node, duration);
if (startHour != -1)
{
reserveNode(node, startHour, duration);
return true;
}
}
return false;
}
```

评分标准

### Part (a) `findContinuousBlock` (5 points)

1. Iteration: Loops over hours in a day (0 to 23 or up to `24 - duration + 1`) without bounds errors. (1 point)
2. Helper method call: Calls `isNodeAvailable` with `nodeNum` and an integer representing the hour in the correct order. (1 point)
3. Tracking contiguous blocks: Maintains an accumulator/counter or boolean flag tracking consecutive available hours and resets correctly when an unavailable hour is encountered. (1 point)
4. Length check: Checks whether the contiguous block reaches the specified `duration`. (1 point)
5. Return values: Correctly calculates and returns the starting hour of the first qualifying block, and returns `-1` if no suitable block is found. (1 point)

### Part (b) `scheduleTask` (4 points)

6. Node loop: Traverses nodes from `startNode` through `endNode` inclusive without bounds errors. (1 point)
7. Method calls: Calls `findContinuousBlock(node, duration)` and `reserveNode(node, startHour, duration)` with appropriate parameters and correct order. (1 point)
8. Guard condition: Checks that the returned starting hour from `findContinuousBlock` is valid (`!= -1` or `>= 0`) before attempting reservation. (1 point)
9. Algorithm completion: Reserves the block on the lowest-numbered available node, immediately returns `true`, and returns `false` if all nodes are checked without finding a block. (1 point)
题目 2 · Class Design
9
This question involves designing a class to track performance scores for an arcade game player.

The `GameScore` class tracks the number of games played, total score accumulated, the highest single-game score, and the number of qualifying games where the score was at or above a specified target threshold.

You will write the complete `GameScore` class, which contains a constructor and four methods.

The `GameScore` constructor takes two parameters:
- A `String` representing the player's tag (identifier).
- An `int` representing the target qualifying score threshold.

In addition to the constructor, the `GameScore` class contains the following methods:
- `recordScore(int score)`: Records the score of a newly completed game, updating the tracking data.
- `getQualifyingGames()`: Returns an `int` representing the number of recorded games with a score greater than or equal to the target threshold.
- `getMaxScore()`: Returns an `int` representing the highest individual game score recorded so far, or `0` if no games have been recorded.
- `getAverageScore()`: Returns a `double` representing the arithmetic mean of all recorded scores, or `0.0` if no games have been recorded.

The following table contains a sample code execution sequence and the corresponding results. The code execution sequence appears in a class other than `GameScore`.

| Statement | Method Call Return Value (blank if none) | Explanation |
| :--- | :--- | :--- |
| `GameScore p1 = new GameScore("ApexHunter", 50);` | | Player "ApexHunter" created with target score 50. |
| `p1.recordScore(60);` | | Records a game with score 60. |
| `p1.recordScore(45);` | | Records a game with score 45. |
| `p1.recordScore(75);` | | Records a game with score 75. |
| `int q = p1.getQualifyingGames();` | `2` | 2 games met or exceeded 50 (scores 60 and 75). |
| `int m = p1.getMaxScore();` | `75` | The highest single game score is 75. |
| `double avg = p1.getAverageScore();` | `60.0` | Average is (60 + 45 + 75) / 3 = 180 / 3 = 60.0. |
| `GameScore p2 = new GameScore("NoviceOne", 100);` | | Player "NoviceOne" created with target score 100. |
| `int q2 = p2.getQualifyingGames();` | `0` | No games recorded yet. |
| `int m2 = p2.getMaxScore();` | `0` | No games recorded yet, returns 0. |
| `double avg2 = p2.getAverageScore();` | `0.0` | No games recorded yet, returns 0.0. |
| `p2.recordScore(30);` | | Records a game with score 30. |
| `double avg3 = p2.getAverageScore();` | `30.0` | Average is 30 / 1 = 30.0. |

Write the complete `GameScore` class. Your implementation must meet all specifications and conform to the examples shown in the table.
查看答案详解

解题

### Complete Class Implementation

```java
public class GameScore
{
private String playerTag;
private int targetScore;
private int numGames;
private int totalScore;
private int qualifyingGames;
private int maxScore;

public GameScore(String tag, int target)
{
playerTag = tag;
targetScore = target;
numGames = 0;
totalScore = 0;
qualifyingGames = 0;
maxScore = 0;
}

public void recordScore(int score)
{
numGames++;
totalScore += score;
if (score >= targetScore)
{
qualifyingGames++;
}
if (score > maxScore)
{
maxScore = score;
}
}

public int getQualifyingGames()
{
return qualifyingGames;
}

public int getMaxScore()
{
return maxScore;
}

public double getAverageScore()
{
if (numGames == 0)
{
return 0.0;
}
return (double) totalScore / numGames;
}
}
```

### Explanation
1. Instance Variables: Declared as `private` to maintain state across method calls (`playerTag`, `targetScore`, `numGames`, `totalScore`, `qualifyingGames`, and `maxScore`).
2. Constructor: Takes a `String` and an `int`, initializes the instance variables, and sets accumulators to zero.
3. `recordScore`: Increments the game counter, adds to the running total score, checks whether the new score reaches the target qualifying threshold, and updates `maxScore` if the new score exceeds the previous maximum.
4. `getQualifyingGames` & `getMaxScore`: Standard accessor methods returning their corresponding stored values.
5. `getAverageScore`: Guards against division by zero by checking if `numGames == 0`, returning `0.0` in that case, and performs floating-point division using a `(double)` cast to return the exact average.

评分标准

Scoring Criteria (9 points total)

1. Class header (1 point)
- Declares `public class GameScore`.
- Penalty: Do not award if class is omitted or declared non-public.

2. Instance variables (1 point)
- Declares appropriate `private` instance variable(s) to track player info, game count, target score, qualifying count, total score, and maximum score.
- Penalty: Do not award if variables are declared `public` or missing private modifiers.

3. Constructor (1 point)
- Declares header `public GameScore(String ..., int ...)` and properly initializes instance variables using parameter values.

4. Method headers (1 point)
- Declares public method headers for all four methods:
- `public void recordScore(int ...)`
- `public int getQualifyingGames()`
- `public int getMaxScore()`
- `public double getAverageScore()`

5. `recordScore` state tracking (1 point)
- Increments game count and accumulates total score.
- Correctly compares `score >= targetScore` and updates qualifying game count.

6. `recordScore` maximum tracking (1 point)
- Correctly identifies and updates the maximum score recorded.

7. `getQualifyingGames` implementation (1 point)
- Returns the correct number of qualifying games.

8. `getMaxScore` implementation (1 point)
- Returns the highest score recorded, or `0` when no games have been recorded.

9. `getAverageScore` calculation (algorithm) (1 point)
- Returns `0.0` when no games have been recorded (guards against division by zero).
- Correctly casts to `double` and divides `totalScore` by `numGames` without integer truncation.
题目 3 · free-response
9
This question involves the analysis of altitude data recorded during an automated drone flight. The `DroneFlightLog` class maintains an `ArrayList` of `Double` objects representing successive altitude measurements (in meters) recorded at regular time intervals.

```java
public class DroneFlightLog
{
/** Guaranteed not to be null and to contain only non-null entries */
private ArrayList altitudes;

/**
* Modifies altitudes by removing all readings that are strictly less than
* or equal to minAltitude, as described in part (a).
* Precondition: minAltitude >= 0.0
/
public void clearGroundReadings(double minAltitude)
{ /
to be implemented in part (a) */ }

/**
* Returns the length (number of recorded points) of the longest consecutive
* strictly ascending sequence of altitudes, as described in part (b).
* Returns 0 if there are no consecutive ascending readings.
/
public int longestAscent()
{ /
to be implemented in part (b) */ }

// There may be instance variables, constructors, and methods not shown.
}
```

(a) Write the `clearGroundReadings` method, which modifies the `altitudes` instance variable by removing all readings that are less than or equal to `minAltitude`. The relative order of all remaining elements in `altitudes` must be preserved.

For example, suppose `altitudes` initially contains the following values:

`[0.0, 12.5, 4.2, 28.0, 5.0, 50.4, 3.8, 65.1]`

After the method call `clearGroundReadings(5.0)`, `altitudes` will contain:

`[12.5, 28.0, 50.4, 65.1]`

Complete the `clearGroundReadings` method below.

```java
/**
* Modifies altitudes by removing all readings that are strictly less than
* or equal to minAltitude, as described in part (a).
* Precondition: minAltitude >= 0.0
*/
public void clearGroundReadings(double minAltitude)
```

(b) Write the `longestAscent` method, which analyzes `altitudes` and returns the number of points in the longest sequence of consecutive readings where each reading is strictly greater than the preceding reading.

An ascent consists of two or more consecutive readings where each reading is strictly greater than the one before it. The length of an ascent is the total number of readings that form that strictly increasing sequence.

- If `altitudes` contains `[15.0, 22.0, 35.0, 18.0, 24.0, 31.0, 45.0, 40.0]`, there are two ascending sequences: `[15.0, 22.0, 35.0]` (length 3) and `[18.0, 24.0, 31.0, 45.0]` (length 4). The method call `longestAscent()` returns `4`.
- If `altitudes` contains `[50.0, 40.0, 30.0, 20.0]`, there are no ascending sequences, so the method returns `0`.
- If `altitudes` contains fewer than 2 elements, the method returns `0`.

Complete the `longestAscent` method below.

```java
/**
* Returns the length (number of recorded points) of the longest consecutive
* strictly ascending sequence of altitudes, as described in part (b).
* Returns 0 if there are no consecutive ascending readings.
*/
public int longestAscent()
```
查看答案详解

解题

### Part (a) Solution

```java
public void clearGroundReadings(double minAltitude)
{
for (int i = altitudes.size() - 1; i >= 0; i--)
{
if (altitudes.get(i) <= minAltitude)
{
altitudes.remove(i);
}
}
}
```

Alternative Forward-Loop Implementation:
```java
public void clearGroundReadings(double minAltitude)
{
int i = 0;
while (i < altitudes.size())
{
if (altitudes.get(i) <= minAltitude)
{
altitudes.remove(i);
}
else
{
i++;
}
}
}
```

### Part (b) Solution

```java
public int longestAscent()
{
if (altitudes.size() < 2)
{
return 0;
}
int currentLength = 1;
int maxLength = 0;
for (int i = 1; i < altitudes.size(); i++)
{
if (altitudes.get(i) > altitudes.get(i - 1))
{
currentLength++;
if (currentLength > maxLength)
{
maxLength = currentLength;
}
}
else
{
currentLength = 1;
}
}
return maxLength;
}
```

评分标准

### Part (a): clearGroundReadings (4 points)
- 1 point: Traverses all elements in `altitudes` without bounds errors (e.g., from `altitudes.size() - 1` down to `0` or using an appropriate `while` loop).
- 1 point: Compares elements of `altitudes` with `minAltitude` using `<=` (or `<` if paired appropriately).
- 1 point: Calls `remove` on `altitudes` with an appropriate integer index.
- 1 point (algorithm): Correctly removes all and only matching elements while preventing index skipping (e.g., backward traversal or conditional index increment).

### Part (b): longestAscent (5 points)
- 1 point: Traverses `altitudes` comparing adjacent/consecutive elements without causing an `IndexOutOfBoundsException` (e.g., starting at index 1 up to `altitudes.size() - 1`).
- 1 point: Correctly accesses and compares adjacent elements (`altitudes.get(i) > altitudes.get(i - 1)` or equivalent).
- 1 point: Tracks/increments current ascending streak when consecutive elements are strictly increasing and resets streak tracker when not increasing.
- 1 point: Updates a maximum streak tracker whenever the current ascending streak exceeds the previous maximum.
- 1 point (algorithm): Correctly determines and returns the length (points in the streak) of the longest ascent, returning `0` if no ascent of length $\ge 2$ exists.
题目 4 · Free Response
9
This question involves a vending machine modeled by a two-dimensional grid of slots containing snacks. The `Snack` class represents an individual snack item.

```java
public class Snack
{
/** Returns the name of this snack /
public String getName()
{ /
implementation not shown */ }

/** Returns the price of this snack in dollars /
public double getPrice()
{ /
implementation not shown */ }

// There may be instance variables, constructors, and methods that are not shown.
}
```

The `SnackDispenser` class represents the vending machine. The instance variable `slots` is a rectangular two-dimensional array of `Snack` references. A location in `slots` contains either a reference to a `Snack` object or `null` if the slot is empty.

```java
public class SnackDispenser
{
/** slots contains at least one row and one column and is initialized in the constructor. */
private Snack[][] slots;

/**
* Returns the total monetary value of all snacks in the specified column.
* Precondition: col is a valid column index in slots.
/
public double getColumnValue(int col)
{ /
to be implemented in part (a) */ }

/**
* Finds and removes the snack with the name specified by snackName that has
* the lowest price among all matching snacks in slots, as described in part (b).
* Returns the removed Snack object, or returns null if no snack with the specified
* name exists in slots.
/
public Snack dispenseCheapest(String snackName)
{ /
to be implemented in part (b) */ }

// There may be instance variables, constructors, and methods that are not shown.
}
```

### Part (a)
Write the `getColumnValue` method, which calculates and returns the total monetary value of all snacks located in column `col` of `slots`. Empty slots (containing `null`) do not contribute to the total. If there are no snacks in column `col`, `getColumnValue` returns `0.0`.

Consider the following $3 \times 4$ grid representing `slots`:

| | Column 0 | Column 1 | Column 2 | Column 3 |
|---|---|---|---|---|
| Row 0 | `"Pretzels"`, $1.50 | `null` | `"Chips"`, $2.00 | `"Granola"`, $1.75 |
| **Row 1** | `null` | `"Chips"`, $1.50 | `null` | `"Granola"`, $2.25 |
| **Row 2** | `"Pretzels"`, $1.25 | `null` | `"Cookies"`, $2.50 | `null` |

- `getColumnValue(0)` returns `2.75` ($1.50 + 1.25$).
- `getColumnValue(1)` returns `1.50` ($1.50$).
- `getColumnValue(2)` returns `4.50` ($2.00 + 2.50$).

Complete the `getColumnValue` method below.

```java
/**
* Returns the total monetary value of all snacks in the specified column.
* Precondition: col is a valid column index in slots.
*/
public double getColumnValue(int col)
```

---

### Part (b)
Write the `dispenseCheapest` method, which finds and removes the snack whose name is equal to `snackName` that has the lowest price among all snacks with that name in `slots`.

- If one or more snacks with the given `snackName` are found, the method removes the matching snack with the minimum price by setting its slot to `null` and returns that `Snack` object. If multiple matching snacks share the same lowest price, the method removes and returns the first one encountered during a standard row-major traversal (top to bottom, left to right).
- If no snack with the specified name exists in `slots`, `slots` is left unchanged and the method returns `null`.

Consider the contents of `slots` shown in the table for part (a):
- The method call `dispenseCheapest("Pretzels")` finds two pretzels (at row 0, col 0 with price $1.50, and row 2, col 0 with price $1.25). The snack at row 2, col 0 is removed and returned, and `slots[2][0]` becomes `null`.
- A subsequent call `dispenseCheapest("Soda")` leaves `slots` unchanged and returns `null`.

Complete the `dispenseCheapest` method below.

```java
/**
* Finds and removes the snack with the name specified by snackName that has
* the lowest price among all matching snacks in slots, as described in part (b).
* Returns the removed Snack object, or returns null if no snack with the specified
* name exists in slots.
*/
public Snack dispenseCheapest(String snackName)
```
查看答案详解

解题

### Canonical Solution

#### Part (a)
```java
public double getColumnValue(int col)
{
double total = 0.0;
for (int r = 0; r < slots.length; r++)
{
if (slots[r][col] != null)
{
total += slots[r][col].getPrice();
}
}
return total;
}
```

#### Part (b)
```java
public Snack dispenseCheapest(String snackName)
{
int minRow = -1;
int minCol = -1;
double minPrice = Double.MAX_VALUE;

for (int r = 0; r < slots.length; r++)
{
for (int c = 0; c < slots[0].length; c++)
{
if (slots[r][c] != null && slots[r][c].getName().equals(snackName))
{
if (slots[r][c].getPrice() < minPrice)
{
minPrice = slots[r][c].getPrice();
minRow = r;
minCol = c;
}
}
}
}

if (minRow != -1)
{
Snack chosen = slots[minRow][minCol];
slots[minRow][minCol] = null;
return chosen;
}
return null;
}
```

评分标准

### Part (a): `getColumnValue` (4 points)
1. Traverse column: Loops over all rows `0` to `slots.length - 1` for the specified `col` with no bounds errors. (1 point)
2. Null guard: Checks that `slots[r][col] != null` before accessing methods on the `Snack` object. (1 point)
3. Accumulate price: Calls `getPrice()` on non-null elements and correctly sums the values. (1 point)
4. Return value: Returns the calculated total sum (including `0.0` when no matching snacks are present). (1 point)

### Part (b): `dispenseCheapest` (5 points)
5. Traverse 2D array: Correctly traverses `slots` in row-major order (nested loops over rows and columns) without bounds errors. (1 point)
6. Null check and name comparison: Correctly guards against `null` and compares snack name using `.equals(snackName)`. (1 point)
7. Identify minimum price snack: Maintains the lowest price and the location (or reference) of the earliest matching snack with that minimum price. (1 point)
8. Update grid: Sets the slot of the identified cheapest snack to `null`. (1 point)
9. Return result: Returns the removed `Snack` object if found, or returns `null` if no match was found. (1 point)

准备好测试自己了吗?

将这些笔记转化为考试练习。获取此课题的无限AI题目,即时批改及详细解析。

练习此课题

想知道自己有几分把握?

thinka 是 DSE 学生在用的 AI 练习应用,提供无限量练习题、即时自动批改和详细解题步骤。超过 100,000 名学生用它确认自己是真的会,而不只是「以为会」。

想练更多同类题型?在 thinka 无限量刷题,即时知道答案。

免费开始练习