Successors: 2017 FRQ 4
A step-by-step solution to the 2017 AP CSA FRQ 4 (Successors), covering searching a 2D array for a value's position and building a full array of successor positions in Java.
Searching a 2D grid for a specific value's location, then mapping every value in that same grid to where its successor lives, is the two-part task behind this AP Computer Science A free-response question.
What This FRQ Tests
- AP CSA units: Unit 8 (2D Array) and Unit 4 (Iteration)
- Core skill: a nested loop that visits every row and column of a 2D array exactly once
- Secondary skill: reusing a method you're told to trust, instead of re-implementing the same search logic a second time
- Official category: "2D Array" — this lines up with the modern fixed FRQ 4 slot, though that fixed FRQ 1–4 ordering itself wasn't standardized until the 2019–2020 Course and Exam Description redesign; 2017's actual printed order was Digits, MultPractice, Phrase, Successors.
The Setup
- A given
Positionclass (its internals aren't shown) represents a(row, column)pair, built withPosition(int r, int c). - You're writing two
staticmethods, both living in one enclosingSuccessorsclass (not shown):findPosition(int num, int[][] intArr)— returns thePositionofnuminsideintArr, ornullif it isn't theregetSuccessorArray(int[][] intArr)— returns a same-sized 2D array ofPositionobjects, where each entry is the position of that cell's successor (the value one greater), ornullfor the single largest value in the array
intArris guaranteed to contain at least one row, and to hold consecutive integer values — though not necessarily in any particular order within the grid.
Part (a): Writing findPosition
The Rule, Broken Down
- Search every cell of the 2D array for one that equals
num. - The moment a match is found, return a new
Positionbuilt from that cell's row and column. - If the entire array is searched with no match, return
null.
Step-by-Step Approach
- Loop over every row index of
intArr. - Inside that, loop over every column index of that row.
- Compare each cell's value to
numwith==, since these are primitiveints, not objects. - The instant a match is found, return
new Position(row, col)immediately — there's no need to keep searching further. - If both loops finish with no match at all, return
nullafter them.
The Code
public static Position findPosition(int num, int[][] intArr)
{
for (int row = 0; row < intArr.length; row++)
{
for (int col = 0; col < intArr[row].length; col++)
{
if (intArr[row][col] == num)
{
return new Position(row, col);
}
}
}
return null;
}
Why Each Piece Matters
==, not.equals()—intArr[row][col]andnumare both primitiveintvalues, not objects, so==is the correct (and only valid) way to compare them.- Returning immediately inside the loop the moment a match is found avoids unnecessary extra work and correctly returns the single match, per the precondition that the array holds consecutive (non-repeating) values.
- Returning
nullonly after both loops finish completely is what correctly signals "never found" — that line is only ever reached once every single cell has already been checked.
Tracing the Example
Using the question's own 3-row, 4-column grid:
col 0 col 1 col 2 col 3
row 0 15 5 9 10
row 1 12 16 11 6
row 2 14 8 13 7
findPosition(8, arr)→ scanning row by row, row 2 column 1 holds8→ returnsPosition(2, 1), matching the question exactly.findPosition(17, arr)→17never appears anywhere in the grid → both loops finish with no match → returnsnull, matching the question exactly.
Common Mistakes to Avoid
- Using
intArr.lengthwhere a column count is needed. For a 2D array declaredintArr[rows][columns],intArr.lengthgives the number of rows — the number of columns for a given row isintArr[row].length(orintArr[0].length, since every row here is the same length). - Comparing with
.equals()instead of==. These are primitiveintvalues —.equals()isn't even a valid call on a primitive. - Writing
(r, c)directly instead ofnew Position(r, c). APositionobject must actually be constructed withnew; there's no shorthand tuple syntax in Java.
Part (b): Writing getSuccessorArray
The Rule, Broken Down
- Build a brand-new 2D array of
Positionobjects, with the same number of rows and columns asintArr. - For every cell in
intArr, find where that cell's value plus one lives, and store thatPositionat the matching(row, column)spot in the new array. - The one cell holding the single largest value in the grid has no successor anywhere in it — no special-case check is needed for this, as explained below.
Step-by-Step Approach
- Create a new
Position[][]with the same dimensions asintArr. - Loop over every row and column of
intArr, using the same nested-loop shape as part (a). - For each cell, call
findPosition(intArr[row][col] + 1, intArr)and store the result at the matching(row, column)position of the new array. - Return the finished array.
The Code
public static Position[][] getSuccessorArray(int[][] intArr)
{
Position[][] successorArr = new Position[intArr.length][intArr[0].length];
for (int row = 0; row < intArr.length; row++)
{
for (int col = 0; col < intArr[row].length; col++)
{
successorArr[row][col] = findPosition(intArr[row][col] + 1, intArr);
}
}
return successorArr;
}
Why Each Piece Matters
- Calling
findPosition(...), instead of rewriting its search logic a second time — the problem explicitly says to assumefindPositionworks correctly and to use it, which is also exactly what the rubric rewards. intArr[row][col] + 1is the value being searched for, notintArr[row][col]itself — passing the cell's own value would find each cell's own position rather than its successor's.- No special check is needed for the largest value. Calling
findPosition(largest + 1, intArr)searches for a value that doesn't exist anywhere in the grid, andfindPositionalready returnsnullfor exactly that case — which is precisely the behavior the successor array needs.
Tracing the Example
Using the question's grid again, a few representative cells:
intArr cell |
Value | Successor searched for | Successor's position | successorArr entry |
|---|---|---|---|---|
| (0,0) | 15 | 16 | (1,1) | (1,1) |
| (0,2) | 9 | 10 | (0,3) | (0,3) |
| (1,1) | 16 (the largest value) | 17 (doesn't exist) | — | null |
| (2,1) | 8 | 9 | (0,2) | (0,2) |
The (2,1) row is the one the question itself highlights — the successor of 8 is 9, which lives at (0,2) — and every entry above matches the question's full 2D successor array exactly, including (1,1) correctly coming out null since 16 is the largest value in the grid.
Common Mistakes to Avoid
- Searching for
intArr[row][col]instead ofintArr[row][col] + 1. This finds each cell's own position, not its successor's. - Reimplementing the search loop from
findPositioninstead of calling it directly. This duplicates logic the problem already told you to trust and reuse. - Sizing the new array incorrectly — it needs to be
new Position[intArr.length][intArr[0].length], matchingintArr's actual dimensions, not a hardcoded size. - Assuming the largest value needs an explicit
if-check to producenull. It doesn't — callingfindPositionwith a value that doesn't exist in the grid already returnsnullon its own.
Key Takeaways
- A 2D array traversal is two nested loops — outer over rows, inner over columns — and that same shape reappears any time the task is "visit every cell."
- When a problem hands you a method and tells you to assume it's correct, call it directly instead of re-deriving its logic — that's both less error-prone and exactly what the rubric is built to reward.
- "The largest value has no successor" doesn't need a special case if the search method being called already returns
nullfor "not found" — let that existing return value carry the meaning instead of adding a redundant check.