Round: 2025 FRQ 3
A step-by-step solution to the 2025 AP CSA FRQ 3 (Round), covering building an ArrayList from a String array and pairing elements from opposite ends toward the middle in Java.
Pairing up tournament competitors by rank — best against worst, and working inward — is the core idea in this AP Computer Science A free-response question, starting with turning a plain array of names into a ranked ArrayList and ending with generating every match for the next round.
What This FRQ Tests
- AP CSA units: Unit 6 (Array) and Unit 7 (ArrayList)
- Core skill: building an
ArrayListof custom objects from aString[], assigning each one a value based on its position - Secondary skill: walking two indices toward each other from opposite ends of a list at the same time
- Official category: "Array/ArrayList" — always FRQ 3 on the AP CSA exam
The Setup
- The given
Competitorclass (not modified) stores a name and rank. - The given
Matchclass (not modified) pairs twoCompetitorobjects together. Roundholds:private ArrayList<Competitor> competitorList
- You're asked to write the constructor and one method:
Round(String[] names)— buildscompetitorList, ranking competitors1throughnin the ordernameslists themArrayList<Match> buildMatches()— pairs up competitors for the next round: best-vs-worst, second-best-vs-second-worst, and so on; if there's an odd number of competitors, the single best-ranked one sits out
Part (a): Writing the Round Constructor
The Rule, Broken Down
- Every name in
namesbecomes oneCompetitorobject. - Competitors appear in
competitorListin the same order they appear innames. - Rank is based on position: the first name is rank
1, and rank increases by1for each name after that.
Step-by-Step Approach
- Initialize
competitorListto a new, emptyArrayList<Competitor>. - Loop over every index of
names. - At each index, construct a
Competitorusing that name and a rank of "index plus one" (since ranks start at1, not0). - Add that
CompetitortocompetitorList.
The Code
public Round(String[] names)
{
competitorList = new ArrayList<Competitor>();
for (int i = 0; i < names.length; i++)
{
competitorList.add(new Competitor(names[i], i + 1));
}
}
Why Each Piece Matters
i + 1for the rank, noti— array indices start at0, but the problem defines rank1as the best, so the rank has to be shifted up by one relative to the index.competitorList.add(...)inside the loop, in index order — this is what guarantees the final list's order matchesnames's order exactly, without needing any extra sorting step.- A brand-new
Competitorobject per name —competitorListholdsCompetitorobjects, not rawStrings, so each name has to be wrapped before it can be added.
Tracing the Example
Using String[] players = {"Alex", "Ben", "Cara"}:
| Index | Name | Rank assigned |
|---|---|---|
| 0 | "Alex" |
1 |
| 1 | "Ben" |
2 |
| 2 | "Cara" |
3 |
Matches the question's expected contents of competitorList exactly.
Common Mistakes to Avoid
- Using the raw index
ias the rank instead ofi + 1— this would incorrectly start ranking at0. - Looping over
competitorListinstead ofnames— at the start of the constructor,competitorListis empty; the array being read from isnames. - Adding the raw
Stringinstead of anew Competitor(...)— this wouldn't compile, sincecompetitorListis typed asArrayList<Competitor>.
Part (b): Writing buildMatches()
The Rule, Broken Down
- If there's an even number of competitors, pair the best with the worst, the second-best with the second-worst, and so on, working inward.
- If there's an odd number of competitors, the single best-ranked competitor sits out, and everyone else pairs up the same way.
- Every pair becomes one
Matchobject added to the returnedArrayList.
Step-by-Step Approach
- Figure out where to start the pairing: index
0if the list's size is even, or index1if it's odd (skipping the best-ranked competitor). - Also track an index starting at the last position in the list.
- Loop while the "start" index is still less than the "end" index: pair those two competitors into a
Match, then move the start index forward and the end index backward. - Stop once the two indices meet or cross — every competitor has been paired (or, for an odd list, correctly left out).
The Code
public ArrayList<Match> buildMatches()
{
ArrayList<Match> matches = new ArrayList<Match>();
int left;
if (competitorList.size() % 2 == 0)
{
left = 0;
}
else
{
left = 1;
}
int right = competitorList.size() - 1;
while (left < right)
{
matches.add(new Match(competitorList.get(left), competitorList.get(right)));
left++;
right--;
}
return matches;
}
Why Each Piece Matters
leftstarts at1for an odd-sized list,0for an even-sized one — this single decision is what correctly excludes the best-ranked competitor only when there's an odd number of competitors, without needing a separate special case anywhere else in the method.rightstarts atcompetitorList.size() - 1, the last valid index — pairing always starts from the worst-ranked competitor working backward.left < rightas the loop condition — this naturally stops the moment the two pointers meet (an exact middle element with nothing left to pair, which can't happen here since a leftover single element only occurs in an odd list and was already skipped) or cross (every remaining competitor has been paired).left++andright--together, once per pair — each pass through the loop consumes exactly one competitor from each end.
Tracing the Example
Using the odd example — competitorList of Alex(1), Ben(2), Cara(3):
- Size is
3(odd) →leftstarts at1,rightstarts at2. left < right(1 < 2): pair index1(Ben) with index2(Cara) → addMatch(Ben, Cara).leftbecomes2,rightbecomes1.left < right?2 < 1is false → loop ends.
Result: one match, between Ben and Cara — matches the question exactly (Alex, the best-ranked, correctly sits out).
Using the even example — Rei(1), Sam(2), Vi(3), Tim(4):
- Size is
4(even) →leftstarts at0,rightstarts at3. - Pair index
0(Rei) with index3(Tim) → addMatch(Rei, Tim).leftbecomes1,rightbecomes2. left < right(1 < 2): pair index1(Sam) with index2(Vi) → addMatch(Sam, Vi).leftbecomes2,rightbecomes1.- Loop ends.
Result: two matches, (Rei, Tim) and (Sam, Vi) — matches the question exactly, in the same order given.
Common Mistakes to Avoid
- Always starting
leftat0, even for an odd-sized list — this would incorrectly include the best-ranked competitor in a match instead of letting them sit out. - Using
left <= rightinstead ofleft < right. For an odd-sized list (after skipping the first competitor), the remaining competitors always pair up evenly, soleftandrightshould never land on the exact same index — but using<=would risk pairing a competitor with themselves if that assumption were ever violated. - Modifying
competitorListitself (e.g., removing paired competitors) instead of just reading from it — the postcondition explicitly requirescompetitorListto be left unchanged.
Key Takeaways
- Converting positions in an array to a 1-indexed value (like rank) is a simple
+ 1on the loop index — easy to get right, easy to accidentally skip. - "Pair the outermost elements, working inward" is a two-pointer pattern: one index starting at the front, one at the back, moving toward each other one step at a time until they meet or cross.
- A single conditional choice of where a pointer starts (rather than a separate code path) is often enough to handle an "odd one out" case cleanly, without duplicating the main pairing logic.