Independent, unofficial worked solutions
Early Solutions to the 2026 AP Computer Science A FRQs | Step by Step
Complete Java solutions for Questions 1-4, with the exact method headers, algorithm design, worked traces, edge cases, correctness explanations, common mistakes, and consolidated exam-ready answers from the uploaded guide.
Contents and Exam-Wide Approach
Purpose of This Guide
The guide translates each prompt into a precise algorithm, develops the Java solution one decision at a time, dry-runs the code on the examples, and explains why the result satisfies every stated precondition and postcondition.
Original guide note: Based on the uploaded paper: ap26-frq-computer-science-a.pdf.
| Section | What is solved | Source pages |
|---|---|---|
| Question 1 | Account constructor; remove each hyphen and the character before it | 3-5 |
| Question 2 | Write the complete Bottle class and maintain object state | 6-7 |
| Question 3 | Match student IDs across two ArrayLists and compare absences | 8-10 |
| Question 4 | Traverse one row of a 2D array; sum points and test colors | 11-13 |
| Final answer sheet | All exam-ready Java responses in one place | This guide |
A Reliable AP CSA Solving Routine
- Identify exactly what must be returned or assigned. Do not add behavior the prompt does not request.
- List the state that must persist between method calls. Persistent state belongs in instance variables; temporary state belongs in local variables.
- Translate each English condition into a Boolean expression, paying attention to words such as less than, both, first, and unchanged.
- Choose a loop whose progress is obvious. State what changes on every iteration so the loop cannot stall.
- Dry-run the most important example and at least one boundary case before finalizing the code.
String contents with .equals, not ==. Respect the supplied method signatures. Trust the stated preconditions, so do not waste time validating inputs that the prompt guarantees are valid. Do not modify a list or field when the postcondition says it must remain unchanged.Solution Conventions
- Code is formatted to compile in ordinary Java, assuming the question-provided classes and hidden methods exist.
- A method can be written in many equivalent ways. The guide favors direct, readable solutions with minimal moving parts.
- Complexity notes are included for understanding, even though the prompts do not ask for Big-O analysis.
String scan..equals.Question 1 - Account
Part A: Constructor That Finds the First Available Username
requestedName itself if it is available; otherwise test requestedName1, requestedName2, requestedName3, and so on, stopping at the first available value and storing it in username.String requestedName, the original base username.username. A constructor has no return value.Step 1: Decide what changes and what stays fixed
requestedNamenever changes. Every numbered candidate must be built from this original base name.candidateis the username currently being tested.suffixis the next integer that will be appended ifcandidateis unavailable.
Step 2: Establish the loop order
- Start
candidateasrequestedNameso the unmodified name is checked first. - Start
suffixat 1 because the first variation must end in 1. - While
candidateis unavailable, replace it withrequestedName + suffixand then advancesuffix. - When the loop ends,
candidateis the first available username; assign it to the instance variable.
Exam-ready constructor
public Account(String requestedName)
{
String candidate = requestedName;
int suffix = 1;
while (!isAvailable(candidate))
{
candidate = requestedName + suffix;
suffix++;
}
username = candidate;
}suffix is 1, the code must create requestedName1. Incrementing suffix after that assignment makes 2 ready for the next iteration without skipping any integer.Question 1A - Dry Run and Correctness
Example trace: requestedName is "Luis-Cruz"
Assume "Luis-Cruz", "Luis-Cruz1", and "Luis-Cruz2" are unavailable, while "Luis-Cruz3" is available.
| Loop test | candidate tested | Available? | Action |
|---|---|---|---|
| 1 | Luis-Cruz | No | Create Luis-Cruz1; suffix becomes 2 |
| 2 | Luis-Cruz1 | No | Create Luis-Cruz2; suffix becomes 3 |
| 3 | Luis-Cruz2 | No | Create Luis-Cruz3; suffix becomes 4 |
| 4 | Luis-Cruz3 | Yes | Exit loop; assign username = "Luis-Cruz3" |
Zero-iteration case
If "PSmith" is available, the while condition is false immediately. No number is appended, and username is assigned "PSmith". This is exactly the required behavior.
Why this constructor is correct
- It calls
isAvailableon every candidate that is considered, including the original requested name. - The generated sequence is
requestedName,requestedName1,requestedName2, ... with no gaps. - The loop stops only when the current candidate is available, so the assigned value is valid.
- Because candidates are tested in increasing suffix order, the first available variation is selected.
Common mistakes to avoid
| Mistake | Why it fails |
|---|---|
Building candidate = candidate + suffix | Produces names such as Name1, then Name12, instead of Name2. |
| Starting suffix at 0 | Tests Name0 even though the prompt says to begin with 1. |
| Checking only numbered versions | Incorrectly ignores the possibility that requestedName itself is available. |
Forgetting to assign username | The local candidate is correct, but the Account object remains uninitialized. |
username.Part B: getShortenedName
String in which every hyphen and the character immediately before that hyphen are omitted, while leaving username unchanged.username.String; do not assign a new value to username.Step 1: Reframe the deletion rule
Each hyphen defines a two-character pair to remove: the character immediately before it and the hyphen itself. The preconditions guarantee that a hyphen is never first, never last, and never adjacent to another hyphen, so every removal pair is well-defined.
Step 2: Scan without modifying username
- Maintain
index, the position currently being considered, andshortened, the output built so far. - If the character after
indexis a hyphen, then the current character is the character that must be removed. Skip both positions by adding 2 toindex. - Otherwise copy the current character into
shortenedand advanceindexby 1. - Return
shortenedafter every position has been handled.
Exam-ready method
public String getShortenedName()
{
String shortened = "";
int index = 0;
while (index < username.length())
{
if (index < username.length() - 1
&& username.substring(index + 1, index + 2).equals("-"))
{
index += 2;
}
else
{
shortened += username.substring(index, index + 1);
index++;
}
}
return shortened;
}username but never assigns a new value to it. Since String objects are immutable and all output is accumulated in the local variable shortened, username is unchanged.Question 1B - Dry Run and Edge Cases
Trace for username = "Amy-Marie-Lin"
| index | Relevant characters | Decision | shortened after action |
|---|---|---|---|
| 0 | A followed by m | Copy A | A |
| 1 | m followed by y | Copy m | Am |
| 2 | y followed by - | Skip y and -; jump to index 4 | Am |
| 4-7 | M, a, r, i | Copy each character | AmMari |
| 8 | e followed by - | Skip e and -; jump to index 10 | AmMari |
| 10-12 | L, i, n | Copy each character | AmMariLin |
Returned value: "AmMariLin"
No-hyphen case
For username = "SammyB3", the look-ahead condition is never true. Every character is copied, so the returned value is "SammyB3".
Boundary observations
- The condition
index < username.length() - 1preventssubstring(index + 1, index + 2)from going past the end of theString. - A final ordinary character is copied normally because there is no following hyphen.
- For a name such as
"A-B-C", the method skipsA-, thenB-, and returns"C".
Common mistakes to avoid
| Mistake | Result |
|---|---|
| Removing only the hyphen | Leaves the character that was supposed to be deleted. |
Changing username directly | Violates the postcondition that username must be unchanged. |
Advancing index by only 1 after a pair is found | The hyphen is processed again or copied incorrectly. |
Using a substring endpoint beyond username.length() | Causes StringIndexOutOfBoundsException. |
"AmMariLin" for "Amy-Marie-Lin", returns an unchanged copy for a no-hyphen name, safely skips every required two-character pair, and never modifies username.Question 2 - Complete Bottle Class
Bottle begins full, loses a requested amount on each valid call, refills to capacity whenever the new amount is strictly below 25% of capacity, and returns the amount remaining after that rule is applied.double bottleCapacity, used as both the permanent capacity and initial amount.updateAmount receives double amountRemoved, updates persistent state, and returns the final double amount.Step 1: Choose the instance variables
| Field | Meaning | Why it must be stored |
|---|---|---|
capacity | Maximum and refill amount | Needed for the 25% threshold and for resetting the bottle. |
amount | Current amount of liquid | Must persist and change across multiple updateAmount calls. |
Step 2: Translate the constructor
The constructor receives the capacity. The prompt says every new bottle is filled to capacity, so both fields initially receive the same value.
Step 3: Translate updateAmount in the required order
- Subtract
amountRemovedfrom the currentamount. - Compare the new amount with
0.25 * capacity. - If the new amount is strictly less than that threshold, reset
amounttocapacity. - Return the final
amount.
Complete class
public class Bottle
{
private double capacity;
private double amount;
public Bottle(double bottleCapacity)
{
capacity = bottleCapacity;
amount = bottleCapacity;
}
public double updateAmount(double amountRemoved)
{
amount -= amountRemoved;
if (amount < 0.25 * capacity)
{
amount = capacity;
}
return amount;
}
}Question 2 - Verification and Boundary Cases
Trace for the 1,000 mL water bottle
| Call | Amount after subtraction | 25% threshold | Refill? | Returned |
|---|---|---|---|---|
updateAmount(400.0) | 600.0 | 250.0 | No | 600.0 |
updateAmount(100.0) | 500.0 | 250.0 | No | 500.0 |
updateAmount(300.0) | 200.0 | 250.0 | Yes -> 1000.0 | 1000.0 |
Trace for the 40 mL shampoo bottle
| Call | Amount after subtraction | Threshold | Reason | Returned |
|---|---|---|---|---|
updateAmount(30.0) | 10.0 | 10.0 | Equal to 25%, not below it | 10.0 |
updateAmount(1.0) | 9.0 | 10.0 | Below 25%, so reset | 40.0 |
amount < 0.25 * capacity. Using <= would incorrectly refill the 40 mL bottle when exactly 10 mL remains.Why the class is correct
capacityremains available for every future call and is never overwritten.amountis updated cumulatively, so each call begins with the amount left by the previous call.- The refill test occurs after removal, matching the wording and examples.
- The precondition guarantees
amountRemovedis positive and no greater than the current amount, so no extra validation is required.
Common mistakes to avoid
| Mistake | Why it fails |
|---|---|
Storing only amount | After several removals, the original capacity is no longer known for refilling. |
| Testing before subtracting | Uses the old amount instead of the amount remaining after use. |
Using <= 25% | Refills at exactly 25%, contradicting the sample. |
| Returning before applying the refill rule | Returns the temporary low amount instead of the reset amount. |
Bottle class above stores both required fields, starts full, subtracts before testing, refills only below 25%, and returns the post-rule amount.Question 3 - Attendance
historyList and mathList, whose elements are CourseRecord objects.int count. Neither list may be changed.Step 1: Recognize the matching problem
A CourseRecord in historyList cannot be compared with just any CourseRecord in mathList. The records must first be matched by student ID. Only after the IDs match should the two absence counts be compared.
Step 2: Use nested traversal
- Visit each history record.
- Search
mathListfor a record with the same student ID. - When a match is found, compare the absence counts and increment
countonly when history is greater. - Break out of the inner loop after the matching ID is processed. The preconditions guarantee no duplicate ID in
mathList.
Exam-ready method
public int moreHistoryThanMathAbsences()
{
int count = 0;
for (CourseRecord historyRecord : historyList)
{
for (CourseRecord mathRecord : mathList)
{
if (historyRecord.getStudentID().equals(
mathRecord.getStudentID()))
{
if (historyRecord.getAbsences()
> mathRecord.getAbsences())
{
count++;
}
break;
}
}
}
return count;
}getStudentID returns a String. Use .equals to compare the character sequences. The == operator would test whether the two variables refer to the same String object, which is not the requirement.Question 3 - Dry Run and Proof of Correct Counting
Students appearing in both lists
| Student ID | History absences | Math absences | History > Math? | Counted? |
|---|---|---|---|---|
| dr03 | 2 | 2 | No - equal | No |
| ot32 | 2 | 1 | Yes | Yes |
| sq98 | 3 | 1 | Yes | Yes |
| ry00 | 1 | 3 | No | No |
Final count: 2
The history-only IDs "rc29" and "br98" are ignored because no matching math record exists. The math-only IDs are never selected by the outer loop and therefore also do not affect the count.
Why the method counts exactly the correct students
- Every
historyListrecord is examined once by the outer loop. - For that record, every
mathListrecord is considered until the matching ID is found or the list ends. countincreases only after both required conditions are true: matching IDs and greater history absences.- Because IDs are unique within each list, a student can increase
countat most once. - The method only calls accessor methods; it never adds, removes, reorders, or replaces list elements, so both lists remain unchanged.
Efficiency
If H is the size of historyList and M is the size of mathList, the worst-case running time is O(H x M), and the extra space is O(1). This direct approach is fully appropriate for the information and tools supplied in the prompt.
Common mistakes to avoid
| Mistake | Consequence |
|---|---|
| Comparing records at the same list index | The lists can be in different orders and have different students. |
Using == for student IDs | May fail even when two IDs contain the same characters. |
| Counting every history record with many absences | Ignores the requirement that the student be enrolled in both courses. |
Using >= instead of > | Incorrectly counts students with equal absence totals, such as dr03. |
moreHistoryThanMathAbsences returns 2 for the sample data and correctly counts only matched student IDs with strictly more history absences.Question 4 - GameBoard
targetRow; return that sum normally, but return twice the sum when every Space in the row has the same color.int targetRow, the index of the row to process in board.Step 1: Track the two facts needed
| Local variable | Purpose |
|---|---|
sum | Accumulates the point values of all spaces in targetRow. |
firstColor | Provides the reference color against which every space is compared. |
allSameColor | Remains true unless a space with a different color is found. |
Step 2: Traverse only the requested row
- Initialize
firstColorfromboard[targetRow][0]. The preconditions guarantee the row has elements and no element isnull. - Loop across the columns in
board[targetRow]. - Add each
Space's points tosum. - Compare each
Space's color withfirstColorusing.equals. If any differs, setallSameColortofalse. - After the loop, return
2 * sumwhenallSameColoristrue; otherwise returnsum.
Exam-ready method
public int getPointsForRow(int targetRow)
{
int sum = 0;
String firstColor = board[targetRow][0].getColor();
boolean allSameColor = true;
for (int col = 0; col < board[targetRow].length; col++)
{
Space current = board[targetRow][col];
sum += current.getPoints();
if (!current.getColor().equals(firstColor))
{
allSameColor = false;
}
}
if (allSameColor)
{
return 2 * sum;
}
return sum;
}Question 4 - Dry Run and Correctness
Row 0 from the sample board
Points: 100 + 100 + 500 + 500 + 100 = 1300. The colors are orange, red, blue, green, and red, so allSameColor becomes false. The method returns 1300.
Row 2 from the sample board
Points: 200 + 300 + 100 + 200 + 200 = 1000. Every Space is red, so allSameColor remains true. The method returns 2 * 1000 = 2000.
| Row | Sum | Color test | Multiplier | Returned value |
|---|---|---|---|---|
| 0 | 1300 | Not all equal | 1 | 1300 |
| 2 | 1000 | All red | 2 | 2000 |
Why the method is correct
- Every element in
targetRowcontributes exactly once tosum. allSameColorstartstrueand can only change tofalse, so one mismatch is enough to record that the row is mixed.- If no mismatch is found, every color equals
firstColorand the sum is doubled exactly once. - The method uses
board[targetRow].length, so it traverses the actual requested row rather than assuming all rows have the same length.
Efficiency
For C columns in targetRow, the running time is O(C) and the extra space is O(1).
Common mistakes to avoid
| Mistake | Why it is wrong |
|---|---|
| Checking only adjacent color pairs incompletely | Can miss a later mismatch unless every element is tested. |
| Doubling points as they are added | The multiplier depends on the entire row and should be applied after the color test is complete. |
Using board.length as the column limit | board.length is the number of rows, not the number of columns in targetRow. |
Using == to compare colors | Tests String identity instead of String contents. |
Final Answer Sheet - Questions 1-4
This section contains only the code a student could enter for the requested responses. Explanations and traces appear in the preceding sections.
Consolidated Exam-Ready Answer Sheet - Questions 1 and 2
Question 1A - Account constructor
public Account(String requestedName)
{
String candidate = requestedName;
int suffix = 1;
while (!isAvailable(candidate))
{
candidate = requestedName + suffix;
suffix++;
}
username = candidate;
}Question 1B - getShortenedName
public String getShortenedName()
{
String shortened = "";
int index = 0;
while (index < username.length())
{
if (index < username.length() - 1
&& username.substring(index + 1, index + 2).equals("-"))
{
index += 2;
}
else
{
shortened += username.substring(index, index + 1);
index++;
}
}
return shortened;
}Consolidated Answer Sheet - Question 2
Complete Bottle class
public class Bottle
{
private double capacity;
private double amount;
public Bottle(double bottleCapacity)
{
capacity = bottleCapacity;
amount = bottleCapacity;
}
public double updateAmount(double amountRemoved)
{
amount -= amountRemoved;
if (amount < 0.25 * capacity)
{
amount = capacity;
}
return amount;
}
}Consolidated Exam-Ready Answer Sheet - Questions 3 and 4
Question 3 - moreHistoryThanMathAbsences
public int moreHistoryThanMathAbsences()
{
int count = 0;
for (CourseRecord historyRecord : historyList)
{
for (CourseRecord mathRecord : mathList)
{
if (historyRecord.getStudentID().equals(
mathRecord.getStudentID()))
{
if (historyRecord.getAbsences()
> mathRecord.getAbsences())
{
count++;
}
break;
}
}
}
return count;
}Question 4 - getPointsForRow
public int getPointsForRow(int targetRow)
{
int sum = 0;
String firstColor = board[targetRow][0].getColor();
boolean allSameColor = true;
for (int col = 0; col < board[targetRow].length; col++)
{
Space current = board[targetRow][col];
sum += current.getPoints();
if (!current.getColor().equals(firstColor))
{
allSameColor = false;
}
}
return allSameColor ? 2 * sum : sum;
}Final Review Checklist
Question-by-question checks
| Question | Final checks |
|---|---|
| 1A | Original name checked first; suffix begins at 1; first available candidate assigned to username. |
| 1B | Both the preceding character and hyphen are skipped; username is not modified; last index is safe. |
| 2 | Two persistent fields; bottle starts full; subtract first; refill only when amount < 25% of capacity. |
| 3 | IDs matched with .equals; both-enrollment condition enforced; comparison is >, not >=; lists unchanged. |
| 4 | Only targetRow traversed; all points summed; all colors compared with .equals; double only after full scan. |
Fast mental tests
- Q1A: If
requestedNameis immediately available, does the constructor append nothing? - Q1B: For
"A-B-C", does the method return"C"? - Q2: At exactly one quarter full, does the bottle stay at that amount?
- Q3: Are equal absence counts excluded?
- Q4: Does a mixed-color row return the undoubled sum even if most colors match?
Suggested 90-minute pacing
A practical plan is 20-22 minutes for Question 1, 18-20 minutes for Question 2, 18-20 minutes for Question 3, 18-20 minutes for Question 4, and the remaining time for compilation-style review. The strongest review targets are String comparison, loop bounds, strict versus non-strict inequalities, and whether required fields are actually updated.
String scan, persistent object state, nested list matching, and a one-row 2D-array traversal. Those patterns are broadly reusable across AP CSA free-response questions.End of detailed solutions.