Title: Sum of Boundary Elements of a 2D Array
In this guide, you will learn how to compute the sum of the boundary elements of a two-dimensional array in Java. The boundary of a matrix is formed by the elements in its first row, last row, first column, and last column, and this is a classic warm-up problem for anyone preparing for coding interviews on arrays.
We will walk through the problem, build an efficient algorithm that visits every boundary cell exactly once, work through a hands-on dry run, examine common mistakes, enumerate the edge cases an interviewer expects you to catch, and finish with follow-up questions that often appear in real interviews.
Understanding the Problem
Given a matrix matrix with rows rows and cols columns, we want the sum of every element that lies on the outer boundary. An element at position (i, j) is on the boundary when i == 0, i == rows - 1, j == 0, or j == cols - 1. Every other element is in the interior and must be ignored.
The subtle requirement is that each boundary element must be counted exactly once. The four corners sit on both a boundary row and a boundary column, so a careless implementation that sums both rows and both columns in full will double count them. We will design the loops so that this never happens.
Approach / Algorithm Steps
- Validate that the matrix is non-null and that both
matrix.lengthandmatrix[0].lengthare positive. - Read the dimensions into
rows = matrix.lengthandcols = matrix[0].length. - If
rows == 1, every element lies on the boundary; sum the single row and return. - If
cols == 1, every element lies on the boundary; sum the single column and return. - Initialize
sum = 0, then walk the first and last rows in a single pass fromj = 0tocols - 1, addingmatrix[0][j]andmatrix[rows - 1][j]tosum. - Walk the first and last columns across only the interior rows from
i = 1torows - 2, addingmatrix[i][0]andmatrix[i][cols - 1]tosum. - Return
sum.
By restricting the side loop to indices 1 through rows - 2, we exclude the four corner cells that have already been counted by the first and last row sweep. This is the heart of the correctness argument.
Java Program
public class BoundarySum {
public static int sumBoundary(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
throw new IllegalArgumentException("Matrix must be non-empty");
}
int rows = matrix.length;
int cols = matrix[0].length;
if (rows == 1) {
int sum = 0;
for (int j = 0; j < cols; j++) {
sum += matrix[0][j];
}
return sum;
}
if (cols == 1) {
int sum = 0;
for (int i = 0; i < rows; i++) {
sum += matrix[i][0];
}
return sum;
}
int sum = 0;
for (int j = 0; j < cols; j++) {
sum += matrix[0][j];
sum += matrix[rows - 1][j];
}
for (int i = 1; i < rows - 1; i++) {
sum += matrix[i][0];
sum += matrix[i][cols - 1];
}
return sum;
}
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
System.out.println("Sum of boundary elements: " + sumBoundary(matrix));
}
}Explanation of the Program
The method sumBoundary starts with a guard clause. If the matrix reference is null, has zero rows, or has an empty first row, we throw IllegalArgumentException so the caller fails fast rather than silently returning a misleading 0.
After the guard, we capture rows and cols once. Two early-return branches handle the degenerate shapes. When rows == 1, the entire row is the boundary, and we sum it with a single loop. When cols == 1, every row contributes exactly one element at column 0, so we sum down that column.
For a matrix with at least two rows and two columns, the first loop walks every column index j and adds both matrix[0][j] and matrix[rows - 1][j]. This covers the entire first and last rows, corners included. The second loop then walks the interior row indices 1 through rows - 2 and adds matrix[i][0] and matrix[i][cols - 1]. Because the corners were already covered by the first loop and are skipped by the second loop’s bounds, every boundary cell is counted exactly once.
Step-by-Step Trace
Let us trace the algorithm on the 3×3 input {{2, 4, 6}, {8, 1, 9}, {3, 5, 7}}, whose expected boundary sum is 44 (the interior element 1 is excluded).
| Step | Loop | Index | Elements added | sum (before) | sum (after) |
|---|---|---|---|---|---|
| 1 | rows loop | j = 0 | 2 + 3 | 0 | 5 |
| 2 | rows loop | j = 1 | 4 + 5 | 5 | 14 |
| 3 | rows loop | j = 2 | 6 + 7 | 14 | 27 |
| 4 | sides loop | i = 1 | 8 + 9 | 27 | 44 |
At the end of each iteration, sum holds the total of every boundary element that has been visited so far, with each element counted exactly once. When both loops finish, sum equals the full boundary sum.
Examples
Example 1: Small 2×3 Matrix
Every cell of a 2×3 matrix sits on the boundary because there are no interior rows. The sum therefore equals the sum of all six elements.
int[][] matrix = {
{1, 2, 3},
{4, 5, 6}
};
// Output: 21Example 2: Single-Row Matrix
A 1×5 matrix hits the rows == 1 early-return branch, so the method sums the row directly without entering the side-column loop.
int[][] matrix = {
{7, 2, 5, 1, 4}
};
// Output: 19Example 3: Rectangular 3×4 Matrix
A 3×4 matrix exercises both loops. The first and last rows contribute 1 + 2 + 3 + 4 + 9 + 10 + 11 + 12 = 52, and the middle row contributes 5 + 8 = 13, giving a total of 65.
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// Output: 65Common Mistakes to Avoid
These are the pitfalls learners actually hit when they first implement this problem, listed from most-common to most-subtle.
- Double counting corners – summing the first and last rows in full and then summing the first and last columns in full inflates the result by the four corner values. Restrict the side-column loop to
i = 1throughrows - 2. - Ignoring single row or single column – a 1×5 input runs the side loop over
i = 1through-1, so nothing executes and the method mistakenly returns0. Branch early whenrows == 1orcols == 1. - Null or zero-length matrix – calling
matrix.lengthonnullthrowsNullPointerException, and readingmatrix[0].lengthon a matrix with no rows throwsArrayIndexOutOfBoundsException. Validate the shape before you dereference it. - Confusing rows and cols – using
matrix[0].lengthfor the row count ormatrix.lengthfor the column count flips the two bounds and crashes on any non-square input. Always deriverows = matrix.lengthandcols = matrix[0].length. - Integer overflow on large grids – a 10,000 by 10,000 matrix of values near
Integer.MAX_VALUEoverflows a 32-bit accumulator. Promotesumtolongif the problem bounds allow such inputs.
Edge Cases to Test
Walk through this checklist before you declare the method complete; most interviewers will probe at least two of these.
- Null matrix reference
- Empty matrix with zero rows
- Single-element matrix (1×1)
- Single-row matrix (1 by n)
- Single-column matrix (n by 1)
- 2×2 matrix with no interior row
- Rectangular matrix where rows differ from columns
- Values near
Integer.MAX_VALUEorInteger.MIN_VALUEthat risk overflow
Additional Considerations
The time complexity is O(rows + cols) because we touch every cell on the boundary exactly once and no interior cell at all. For an n x n matrix this is O(n), which is strictly better than the O(n * n) cost of scanning the full grid and testing each cell for membership on the boundary.
The space complexity is O(1); we only hold the running sum and the two dimension variables. The Integer.MAX_VALUE edge case matters precisely because the algorithm is otherwise cheap enough that interviewers routinely raise the input size until overflow becomes real. If overflow is possible, change sum to long and return a long; the extra width costs nothing in asymptotic terms.
A common refactor is to merge the two loops into a single nested scan that checks the boundary predicate i == 0 || i == rows - 1 || j == 0 || j == cols - 1. That version is easier to read, but it costs O(rows * cols) instead of O(rows + cols), so prefer the two-loop form whenever the matrix is large.
Interview Follow-up Questions
Expect the interviewer to extend the base problem along one or more of these axes. Each hint names the approach rather than the full solution.
- What if you need only the sum of the four corners? – index them directly as
matrix[0][0] + matrix[0][cols - 1] + matrix[rows - 1][0] + matrix[rows - 1][cols - 1], with a special case when either dimension is1. - What if the matrix is jagged (rows have different lengths)? – compute the first and last valid column index per row, and treat every element of the first and last rows as boundary.
- How would you compute the sum of the k-th inner layer instead? – offset the four index bounds by
kand reuse the same two-loop pattern, stopping when the inner region has one or zero rows left. - How would you handle a matrix that arrives as a stream of rows and does not fit in memory? – buffer only the most recent row; add every element of the first row in full, add only the first and last cell of each middle row, and add every element of the final row when end-of-stream is detected.
- Can you answer boundary-sum queries for many submatrices in O(1) after preprocessing? – build a 2D prefix sum over the whole matrix and a second 2D prefix sum restricted to the interior; subtract to get the boundary sum of any query rectangle.
Conclusion
Summing the boundary of a 2D array is a small problem with a big lesson: careful loop bounds let you touch each cell exactly once, and early branches for degenerate shapes keep the code honest. Once you internalize the i = 1 to rows - 2 trick for the side columns, the same pattern transfers to spiral traversal, matrix rotation, and layer-by-layer problems.
Try adapting the code to return a long, to count only even boundary values, or to compute the boundary of an arbitrary inner layer. You can learn more about array problems and interview warm-ups here: Arrays.



