Implementing 2D Array Algorithms
Why this matters
Imagine you're helping run the concession stand for the school's basketball team. You track sales in a spreadsheet: rows are for different snacks (popcorn, pretzels, soda), and columns are for each quarter of the game. At the end of the night, you need answers. What was our best-selling item? How much money did we make in the 4th quarter? Did any item sell out completely?
A 2D array is just like that spreadsheet. It's a grid for organizing information. Knowing how to write algorithms for 2D arrays lets you answer all those questions and more. You're not just storing data; you're making sense of it. Today, we'll break down the standard "recipes"—the algorithms—for pulling powerful insights from these data grids.
Concept overview
flowchart TD
A[Start] --> B{Initialize maxVal = grid[0][0]};
B --> C{For each row 'r' in grid};
C --> D{For each column 'c' in grid[r]};
D --> E{Is grid[r][c] > maxVal?};
E -- Yes --> F{maxVal = grid[r][c]};
E -- No --> G[Next column];
F --> G;
G --> D;
D -- End of Row --> H[Next row];
H --> C;
C -- End of Grid --> I[Return maxVal];
I --> J[End];
Core explanation
You've learned how to create and traverse 2D arrays. Now, let's put them to work. An algorithm is just a set of steps to solve a problem. For 2D arrays, most algorithms involve a nested loop to visit every element, but what you do inside that loop is what matters.
Let's use a great analogy: a 2D array is like a digital spreadsheet. The rows and columns are just like in Excel. The algorithms we'll write are like creating our own SUM(), MAX(), or COUNTIF() functions.
Aggregations: Sum, Average, Min & Max
These algorithms "boil down" the entire grid (or a part of it) into a single number. They all follow a similar pattern:
- 1Initializea variable to hold your result.
- 2Traversethe array (or the specific row/column) with nested loops.
- 3Updateyour variable at each element.
- 4Returnthe final result after the loops finish.
Finding a Sum or Average
Let's say we have a 2D array of integers representing weekly sales for different products at a farmer's market in Dallas.
int[][] weeklySales = {
{150, 200, 160, 210}, // Product A
{120, 130, 140, 125}, // Product B
{180, 190, 220, 240} // Product C
};
To find the total sales of all products, we sum every element.
public static int getTotalSales(int[][] sales) {
int total = 0; // 1. Initialize
for (int r = 0; r < sales.length; r++) {
for (int c = 0; c < sales[0].length; c++) {
total += sales[r][c]; // 3. Update
}
}
return total; // 4. Return
}
To find the average, you'd do the same thing, but at the end, divide by the total number of elements: sales.length * sales[0].length.
What if you only want the sum for a specific row (e.g., total sales for Product B, which is row 1)? You just use a single loop for that row's columns.
public static int getRowSum(int[][] sales, int row) {
int rowTotal = 0;
// Note: We only loop through the columns of the specified row
for (int c = 0; c < sales[row].length; c++) {
rowTotal += sales[row][c];
}
return rowTotal;
}
Finding the Minimum or Maximum
This is almost identical, but the update step is a comparison. To find the highest sale amount in the whole grid:
public static int getMaximumSale(int[][] sales) {
// 1. Initialize with the VERY FIRST element.
int maxVal = sales[0][0];
for (int r = 0; r < sales.length; r++) {
for (int c = 0; c < sales[0].length; c++) {
// 3. Update if we find a bigger value
if (sales[r][c] > maxVal) {
maxVal = sales[r][c];
}
}
}
return maxVal; // 4. Return
}
Property Checks: Counting and Searching
These algorithms check elements against a certain condition.
- Count how many elements have a property.
- Determine if at least one element has a property.
- Determine if all elements have a property.
Let's imagine a boolean[][] grid representing a tic-tac-toe board, where true means 'X' is in that spot.
Counting Elements with a Property
How many 'X's are on the board? This is just like finding a sum, but we add 1 instead of the element's value.
public static int countXs(boolean[][] board) {
int count = 0;
for (int r = 0; r < board.length; r++) {
for (int c = 0; c < board[0].length; c++) {
if (board[r][c] == true) { // The property check
count++;
}
}
}
return count;
}
Finding "At Least One"
Does the board have at least one 'X'? You can stop searching as soon as you find one.
public static boolean hasAtLeastOneX(boolean[][] board) {
for (int r = 0; r < board.length; r++) {
for (int c = 0; c < board[0].length; c++) {
if (board[r][c] == true) {
return true; // Found one! Exit immediately.
}
}
}
// If we get here, the loops finished without finding any.
return false;
}
Determining if "All" Have a Property
This one is tricky. The logic is inverted. You assume the property is true for all elements, and you search for a single counterexample that proves you wrong.
Let's say we have an array of test scores and want to see if every student in a particular class (row) passed (scored >= 60).
public static boolean allPassedInRow(int[][] scores, int row) {
for (int c = 0; c < scores[row].length; c++) {
if (scores[row][c] < 60) {
// Found a failing score. We can immediately say they didn't ALL pass.
return false;
}
}
// If the loop completes without finding any failing scores, then they all passed.
return true;
}
Positional and Structural Algorithms
These algorithms care about the position of elements relative to each other.
Accessing Consecutive Pairs
To check for adjacent identical numbers in a row, you compare grid[r][c] with grid[r][c+1]. The key is to stop your column loop one step early to avoid an ArrayIndexOutOfBoundsException.
// Check for any adjacent duplicates in a single row
for (int c = 0; c < grid[row].length - 1; c++) { // Notice the "- 1"
if (grid[row][c] == grid[row][c+1]) {
System.out.println("Found a pair!");
}
}
Finding Duplicates
To find if there are any duplicate values in the entire 2D array, a common (though not the most efficient) approach is to use nested loops to compare every element to every other element. This is a bit more complex, often involving four nested loops. The AP exam is more likely to ask you to find duplicates within a single row or column.
Shifting and Rotating
This is a classic AP problem. Let's shift a row to the left. The element at index 0 is lost, grid[r][1] moves to grid[r][0], grid[r][2] moves to grid[r][1], and so on.
public static void shiftRowLeft(int[] row) {
// To rotate, you'd save this value first: int first = row[0];
for (int c = 0; c < row.length - 1; c++) {
row[c] = row[c + 1];
}
// The last element can be set to 0 or some other default.
// If rotating, you'd set it to the saved 'first' value.
row[row.length - 1] = 0;
}
To use this on a 2D array, you'd pass myGrid[someRow] to this method.
Reversing a Row or Column
To reverse a row, you swap the first and last elements, then the second and second-to-last, and so on, until you meet in the middle. This is often called the "two-pointer" technique.
public static void reverseRow(int[] row) {
int start = 0;
int end = row.length - 1;
while (start < end) {
// Swap the elements
int temp = row[start];
row[start] = row[end];
row[end] = temp;
// Move the pointers
start++;
end--;
}
}
These standard algorithms are your toolkit. The AP exam will test you by asking you to implement them directly or to combine them to solve a slightly new problem. Practice them until the patterns feel second nature.
See it in action
Worked examples
Let's walk through a few problems to see these algorithms in action. The key is to break down the problem and identify which pattern to use.
Finding the Highest Score in a Column
Problem: You have a 2D array gradebook where rows represent students and columns represent assignments. The columns are: Homework 1, Homework 2, Midterm, Final Exam. Find the highest score achieved by any student on the Final Exam (column index 3).
int[][] gradebook = {
{90, 95, 88, 92}, // Student 0: Priya
{75, 80, 78, 85}, // Student 1: Carlos
{100, 98, 95, 99} // Student 2: Aaliyah
};
int finalExamCol = 3;
Solution Walkthrough:
- 1Identify the GoalWe need to find the maximum value, but only within a specific column. This is a "Max" algorithm on a subsection of the array.
- 2Choose the AlgorithmWe'll use the find-maximum pattern. We need to loop, but instead of nested loops for the whole grid, we'll loop down the rows, keeping the column index fixed.
- 3InitializeWe need a variable to store the maximum score. The safest way is to initialize it with the first value we'll check: the score in the first student's final exam column.
int maxScore = gradebook[0][finalExamCol];// This is 92. - 4Loop and CompareNow, we'll loop through the rest of the students (rows) and compare their final exam score to our current
maxScore.- Start the loop at
r = 1because we already usedr = 0to initialize. - Iteration
r = 1(Carlos): Isgradebook[1][3](which is 85) greater thanmaxScore(92)? No.maxScoreremains 92. - Iteration
r = 2(Aaliyah): Isgradebook[2][3](which is 99) greater thanmaxScore(92)? Yes. We updatemaxScoreto 99.
- Start the loop at
- Final Result: The loop finishes. The final value of
maxScoreis 99.
Code:
public int getHighestInColumn(int[][] grades, int col) {
// Handle empty array case to be robust
if (grades.length == 0) return -1; // Or throw an exception
int maxScore = grades[0][col]; // Initialize with the first row's value in that col
for (int r = 1; r < grades.length; r++) {
if (grades[r][col] > maxScore) {
maxScore = grades[r][col];
}
}
return maxScore;
}
Shifting a Row for a Seating Chart
Problem: A theater in Chicago has a seating chart represented by a 2D array of strings. An usher needs to ask an entire row of patrons to shift one seat to the right to make space for a wheelchair. The person in the last seat moves out of the row. The first seat becomes empty. Write a method to do this for a given row.
Solution Walkthrough:
- 1Identify the GoalWe need to shift all elements in a single row one position to the right. This is a positional algorithm.
- 2The TrapIf you start at the beginning of the row and copy
row[0]torow[1], you've just overwritten the value that was supposed to go intorow[2]!row[1] = row[0];row[2] = row[1];// Oops!row[1]is now the same asrow[0].
- 3Do This InsteadTo avoid overwriting values you still need, you must start from the end of the row and work backwards.
- 4Loop and Copy
- The value at
row[length - 2]goes intorow[length - 1]. - The value at
row[length - 3]goes intorow[length - 2]. - ...and so on, until the value at
row[0]goes intorow[1].
- The value at
- 5Handle the First SeatAfter the loop, the first seat (
row[0]) needs to be set to "empty".
Code:
public void shiftRowRight(String[] row) {
// Start from the second-to-last element and go down to the first.
for (int i = row.length - 1; i > 0; i--) {
row[i] = row[i - 1]; // Copy the element from the left into the current spot.
}
// Now, clear the first seat.
row[0] = "empty";
}
This is a crucial pattern. For shifts, think about which direction you need to loop from to avoid destroying data you haven't processed yet. For a right shift, loop from the right. For a left shift, loop from the left.
Try it yourself
Ready to try a couple on your own? Don't worry about writing a full program, just focus on the logic for the method itself.
Problem 1: The Vending Machine
You're given a 2D integer array inventory where each cell represents the quantity of a snack in a vending machine in Seattle. Write a method isAnythingSoldOut(int[][] inventory) that returns true if any snack has a quantity of 0, and false otherwise.
Hint: This is an "at least one" algorithm. What does that mean for your loops? Can you stop early?
Problem 2: Reversing a Column
You're given a 2D array gameBoard. Write a method reverseColumn(String[][] gameBoard, int col) that reverses the order of the elements in a specified column. For example, the element at the top of the column should swap with the element at the bottom, and so on.
Hint: This is very similar to reversing a 1D array. Use the two-pointer technique (a top index starting at 0, a bottom index starting at the last row). What will your while loop condition be? Remember to use a temporary variable for swapping.
Practice — 8 questions
In simple terms, this topic is about writing code to perform common tasks on 2D arrays, like finding the highest value, calculating totals, or shifting elements around in a grid.
int[][] weeklySales = {
{150, 200, 160, 210}, // Product A
{120, 130, 140, 125}, // Product B
{180, 190, 220, 240} // Product C
};
- 4.13.A: Develop code for standard and original algorithms for a particular context or specification that involves 2D arrays and determine the result of these algorithms.
- 4.13.A.1
- There are standard algorithms that utilize 2D array traversals to: • determine a minimum or maximum value of all the elements or for a designated row, column, or other subsection • compute a sum or average of all the elements or for a designated row, column, or other subsection • determine if at least one element has a particular property in the entire 2D array or for a designated row, column, or other subsection • determine if all elements of the 2D array or a designated row, column, or other subsection have a particular property • determine the number of elements in the 2D array or in a designated row, column, or other subsection having a particular property • access all consecutive pairs of elements • determine the presence or absence of duplicate elements in the 2D array or in a designated row, column, or other subsection • shift or rotate elements in a row left or right or in a column up or down • reverse the order of the elements in a row or column
flowchart TD
A[Start] --> B{Initialize maxVal = grid[0][0]};
B --> C{For each row 'r' in grid};
C --> D{For each column 'c' in grid[r]};
D --> E{Is grid[r][c] > maxVal?};
E -- Yes --> F{maxVal = grid[r][c]};
E -- No --> G[Next column];
F --> G;
G --> D;
D -- End of Row --> H[Next row];
H --> C;
C -- End of Grid --> I[Return maxVal];
I --> J[End];
Read what Saavi narrates
Hi everyone, it's Saavi from Shrutam.
Let's talk about something you probably use every day without thinking: a spreadsheet. Imagine you're running a concession stand for the school basketball game. You've got rows for popcorn, pretzels, and soda... and columns for each quarter of the game. At the end of the night, you want to know what your best-selling item was, or how much money you made in the fourth quarter.
A 2D array in computer science is just like that spreadsheet. It's a grid for organizing information. And today, we're going to learn the recipes, or algorithms, to ask those same kinds of questions with our code. Think of it like building your own SUM or MAX functions for a spreadsheet, but from scratch.
Let's take a concrete example. Imagine a vending machine inventory is stored in a 2D array. Rows are the different shelves, and columns are the slots on each shelf. Each cell holds a number... the quantity of that snack.
Let's say the problem is to find the highest quantity of any single item in the entire machine. How would we do that?
First, we need a variable to keep track of the highest number we've seen so far. Let's call it `maxQuantity`. Now, here's a key tip: we should initialize `maxQuantity` with the value from the very first slot, say, `inventory[0][0]`.
Then, we start our journey through the grid. We'll use a nested loop... an outer loop for the rows, and an inner loop for the columns. At every single slot, we'll ask a simple question: is the number in this slot bigger than our current `maxQuantity`? If it is, we've found a new maximum! So, we update `maxQuantity` to this new, higher number. If it's not bigger, we just move on.
After our loops have visited every single slot in the machine, our `maxQuantity` variable will hold the largest value from the entire grid. We just have to return that value.
This pattern is super common. A really frequent mistake I see is when students initialize their maximum variable to zero. It seems logical, but what if the numbers could be negative? For example, if you were tracking profit and had a loss. Your code would incorrectly say the max is zero. By starting with the first actual value from the array, your code will always work correctly.
These algorithms are your new toolkit. Practice them, and you'll be able to make sense of any grid of data the AP exam throws at you. You've got this.
For a 2D array `grid`, `grid.length` gives you the number of **rows**. `grid[0].length` gives you the number of **columns** (assuming it's a rectangular array). Using the wrong one will either cause an `ArrayIndexOutOfBoundsException` or lead to incorrect logic.
Remember: `grid.length` is the length of the "outer" array, which contains the rows. `grid[0].length` is the length of the "inner" array (the first row), which contains the columns. Say it out loud: "rows, then columns."
If you're finding a maximum and all numbers in the array are negative, your code will incorrectly return 0. If you're finding a minimum and all numbers are greater than 0, your code might work by luck, but it's not robust.
Initialize your min/max variable to the *first element* in the array or subsection you are searching (e.g., `int maxVal = grid[0][0];`). This guarantees your starting point is a real value from the dataset.
Students often write code like this: `if (condition is true) { return true; } else { return false; }` inside the loop. This causes the method to return a decision based on only the very first element it checks.
Assume the best, look for the worst. Return `false` *inside* the loop as soon as you find one element that *fails* the condition. Only return `true` *after* the loop has finished completely without finding any failures.
A loop like `for (int c = 0; c < row.length; c++)` that accesses `row[c+1]` will crash when `c` is at its last value, because `c+1` will be out of bounds.
When your loop body accesses `[i+1]`, your loop condition must be `< length - 1`. When it accesses `[i-1]`, your loop can start at `i = 1`. Always trace the first and last iterations of your loop mentally.
If you shift elements to the right by starting at the left (`row[1] = row[0]`, `row[2] = row[1]`, etc.), you will just copy the first element all the way across the array.
For a right shift, loop from right to left. For a left shift, loop from left to right. Think about which data you need to preserve before overwriting it.