CompSci.rocks
FRQcsapa

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 Position class (its internals aren't shown) represents a (row, column) pair, built with Position(int r, int c).
  • You're writing two static methods, both living in one enclosing Successors class (not shown):
    • findPosition(int num, int[][] intArr) — returns the Position of num inside intArr, or null if it isn't there
    • getSuccessorArray(int[][] intArr) — returns a same-sized 2D array of Position objects, where each entry is the position of that cell's successor (the value one greater), or null for the single largest value in the array
  • intArr is 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

  1. Search every cell of the 2D array for one that equals num.
  2. The moment a match is found, return a new Position built from that cell's row and column.
  3. If the entire array is searched with no match, return null.

Step-by-Step Approach

  1. Loop over every row index of intArr.
  2. Inside that, loop over every column index of that row.
  3. Compare each cell's value to num with ==, since these are primitive ints, not objects.
  4. The instant a match is found, return new Position(row, col) immediately — there's no need to keep searching further.
  5. If both loops finish with no match at all, return null after 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] and num are both primitive int values, 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 null only 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 holds 8 → returns Position(2, 1), matching the question exactly.
  • findPosition(17, arr)17 never appears anywhere in the grid → both loops finish with no match → returns null, matching the question exactly.

Common Mistakes to Avoid

  • Using intArr.length where a column count is needed. For a 2D array declared intArr[rows][columns], intArr.length gives the number of rows — the number of columns for a given row is intArr[row].length (or intArr[0].length, since every row here is the same length).
  • Comparing with .equals() instead of ==. These are primitive int values — .equals() isn't even a valid call on a primitive.
  • Writing (r, c) directly instead of new Position(r, c). A Position object must actually be constructed with new; there's no shorthand tuple syntax in Java.

Part (b): Writing getSuccessorArray

The Rule, Broken Down

  1. Build a brand-new 2D array of Position objects, with the same number of rows and columns as intArr.
  2. For every cell in intArr, find where that cell's value plus one lives, and store that Position at the matching (row, column) spot in the new array.
  3. 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

  1. Create a new Position[][] with the same dimensions as intArr.
  2. Loop over every row and column of intArr, using the same nested-loop shape as part (a).
  3. For each cell, call findPosition(intArr[row][col] + 1, intArr) and store the result at the matching (row, column) position of the new array.
  4. 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 assume findPosition works correctly and to use it, which is also exactly what the rubric rewards.
  • intArr[row][col] + 1 is the value being searched for, not intArr[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, and findPosition already returns null for 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 of intArr[row][col] + 1. This finds each cell's own position, not its successor's.
  • Reimplementing the search loop from findPosition instead 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], matching intArr's actual dimensions, not a hardcoded size.
  • Assuming the largest value needs an explicit if-check to produce null. It doesn't — calling findPosition with a value that doesn't exist in the grid already returns null on 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 null for "not found" — let that existing return value carry the meaning instead of adding a redundant check.

Related FRQs