Topic 4.15 — Developing Algorithms Using 2D Arrays

Goal: apply common algorithm patterns to 2D arrays (searching, counting, finding max/min, updating), and handle boundaries correctly when working with neighbors.

The big idea

2D array algorithms are mostly “regular” algorithms plus: nested loops and careful bounds.

Always decide your traversal first (row-major is the default), then implement the pattern (sum/count/search/update).

Algorithm patterns you should recognize

PatternWhat you do
Sum / averageaccumulate values as you traverse
Countincrement when a condition is true
Find max/minkeep a “best so far” variable
Searchcheck each element until found
Update/replaceassign back to grid[r][c]
Neighbor-baseduse r±1, c±1 with bounds checks

Sum / average

int sum = 0;
int count = 0;

for (int r = 0; r < grid.length; r++) {
  for (int c = 0; c < grid[r].length; c++) {
    sum += grid[r][c];
    count++;
  }
}

double avg = (double) sum / count;

Count with a condition

Example: count values that are even.

int evens = 0;
for (int r = 0; r < grid.length; r++) {
  for (int c = 0; c < grid[r].length; c++) {
    if (grid[r][c] % 2 == 0) evens++;
  }
}

Find max / min

Assume the array has at least one element.

int max = grid[0][0];

for (int r = 0; r < grid.length; r++) {
  for (int c = 0; c < grid[r].length; c++) {
    if (grid[r][c] > max) {
      max = grid[r][c];
    }
  }
}

Search for a target

boolean found = false;

for (int r = 0; r < grid.length; r++) {
  for (int c = 0; c < grid[r].length; c++) {
    if (grid[r][c] == target) {
      found = true;
    }
  }
}

(You can also return early in a method if allowed.)

Update / replace

Example: replace all negatives with 0.

for (int r = 0; r < grid.length; r++) {
  for (int c = 0; c < grid[r].length; c++) {
    if (grid[r][c] < 0) {
      grid[r][c] = 0;
    }
  }
}

Neighbor-based algorithms (boundaries matter)

If you look at “right neighbor” [r][c+1], don’t let c reach the last column.

// Count how many times a value is less than the value to its right
int incRight = 0;

for (int r = 0; r < grid.length; r++) {
  for (int c = 0; c < grid[r].length - 1; c++) { // -1 so c+1 is safe
    if (grid[r][c] < grid[r][c + 1]) {
      incRight++;
    }
  }
}

Neighbor example: “down” neighbor

For [r+1][c], stop r at the second-to-last row.

int downPairs = 0;

for (int r = 0; r < grid.length - 1; r++) { // -1 so r+1 is safe
  for (int c = 0; c < grid[r].length; c++) {
    // if rectangular, this is safe; for jagged you'd need extra checks
    if (grid[r][c] == grid[r + 1][c]) {
      downPairs++;
    }
  }
}

Jagged arrays + neighbors = extra caution

If rows have different lengths, grid[r+1][c] might not exist even when r+1 exists.

// Safe-ish approach for jagged arrays when comparing down-neighbors:
for (int r = 0; r < grid.length - 1; r++) {
  int cols = Math.min(grid[r].length, grid[r + 1].length);
  for (int c = 0; c < cols; c++) {
    // grid[r][c] and grid[r+1][c] are both valid
  }
}

Quick self-check

  1. What traversal pattern is most common for 2D arrays?
  2. Which variable usually tracks rows? columns?
  3. How do you safely compare a cell to its right neighbor?
  4. How do you safely compare a cell to its down neighbor?
  5. Why do jagged arrays require extra care for neighbor algorithms?

← Back to Unit 4 topics