1572. Matrix Diagonal Sum
Problem Description
You are given a square matrix mat
(meaning it has the same number of rows and columns). Your task is to calculate the sum of all elements on both diagonals of the matrix.
The matrix has two diagonals:
- Primary diagonal: Elements where the row index equals the column index (i.e.,
mat[0][0]
,mat[1][1]
,mat[2][2]
, etc.) - Secondary diagonal: Elements where the row index plus column index equals
n-1
, wheren
is the size of the matrix (i.e.,mat[0][n-1]
,mat[1][n-2]
,mat[2][n-3]
, etc.)
You need to sum all elements on both diagonals. However, be careful with the center element in odd-sized matrices - if an element appears on both diagonals (which happens only at the center of odd-sized matrices), count it only once in your sum.
For example, in a 3×3 matrix:
- Primary diagonal elements are at positions
[0][0]
,[1][1]
,[2][2]
- Secondary diagonal elements are at positions
[0][2]
,[1][1]
,[2][0]
- The element at
[1][1]
is on both diagonals, so it should be counted only once
The solution iterates through each row i
and adds the element at position [i][i]
(primary diagonal) and the element at position [i][n-i-1]
(secondary diagonal). When these two positions are the same (i.e., i == n-i-1
), which happens at the center of odd-sized matrices, the element is added only once.
Intuition
The key insight is that in a square matrix, we can identify diagonal elements using a simple pattern. For any row i
, the primary diagonal element is always at column i
(same as the row index), and the secondary diagonal element is at column n - i - 1
(counting from the opposite end).
Instead of thinking about diagonals as separate entities to traverse, we can process the matrix row by row. As we go through each row, we know exactly where the diagonal elements are located without needing to search for them.
For a row at index i
:
- Primary diagonal element:
mat[i][i]
- Secondary diagonal element:
mat[i][n - i - 1]
This pattern holds for every row in the matrix. The beauty of this approach is that we only need a single loop through the rows, and for each row, we can directly access both diagonal elements in constant time.
The tricky part is handling the center element in odd-sized matrices. When the matrix has an odd dimension (like 3×3 or 5×5), there's a center element that belongs to both diagonals. This happens when i == n - i - 1
, which simplifies to i == (n - 1) / 2
- exactly the middle row. At this point, both diagonal positions point to the same element, so we need to add it only once to avoid double-counting.
This row-by-row approach is efficient because we visit each diagonal element exactly once, giving us a time complexity of O(n)
where n
is the number of rows, rather than O(n²)
if we were to check every element in the matrix.
Solution Approach
The implementation follows a straightforward row-by-row traversal pattern. We iterate through each row of the matrix and calculate the sum of diagonal elements efficiently.
Here's how the algorithm works:
-
Initialize the sum: Start with
ans = 0
to accumulate the diagonal sum. -
Get matrix dimension: Store
n = len(mat)
to know the size of our square matrix. -
Iterate through rows: Use
enumerate(mat)
to get both the row indexi
and the row contentrow
simultaneously. -
Calculate diagonal positions: For each row
i
:- The primary diagonal element is at position
row[i]
- The secondary diagonal element position is calculated as
j = n - i - 1
- The secondary diagonal element is at position
row[j]
- The primary diagonal element is at position
-
Handle the center element: When adding elements to the sum:
- Always add the primary diagonal element:
row[i]
- For the secondary diagonal element, check if
j == i
(which means we're at the center of an odd-sized matrix) - If
j == i
, add0
(to avoid double-counting the same element) - Otherwise, add
row[j]
This is elegantly handled with the expression:
ans += row[i] + (0 if j == i else row[j])
- Always add the primary diagonal element:
-
Return the result: After processing all rows, return the accumulated sum.
The algorithm makes a single pass through the matrix rows, accessing exactly two elements per row (or one element for the center row in odd-sized matrices). This gives us:
- Time Complexity:
O(n)
wheren
is the number of rows - Space Complexity:
O(1)
as we only use a constant amount of extra space
The solution elegantly avoids nested loops and unnecessary condition checks by using the mathematical relationship between row indices and diagonal positions.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with a 3×3 matrix:
mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Step 1: Initialize
ans = 0
(our running sum)n = 3
(matrix dimension)
Step 2: Process Row 0 (i=0)
- Row content:
[1, 2, 3]
- Primary diagonal element:
row[0] = 1
- Secondary diagonal position:
j = 3 - 0 - 1 = 2
- Secondary diagonal element:
row[2] = 3
- Check if center:
j == i
? →2 == 0
? → No - Add to sum:
ans = 0 + 1 + 3 = 4
Step 3: Process Row 1 (i=1)
- Row content:
[4, 5, 6]
- Primary diagonal element:
row[1] = 5
- Secondary diagonal position:
j = 3 - 1 - 1 = 1
- Secondary diagonal element:
row[1] = 5
- Check if center:
j == i
? →1 == 1
? → Yes! (This is the center) - Add to sum:
ans = 4 + 5 + 0 = 9
(add 0 instead of 5 to avoid double-counting)
Step 4: Process Row 2 (i=2)
- Row content:
[7, 8, 9]
- Primary diagonal element:
row[2] = 9
- Secondary diagonal position:
j = 3 - 2 - 1 = 0
- Secondary diagonal element:
row[0] = 7
- Check if center:
j == i
? →0 == 2
? → No - Add to sum:
ans = 9 + 9 + 7 = 25
Final Result: 25
The diagonal elements we summed were:
- Primary diagonal: 1, 5, 9 (sum = 15)
- Secondary diagonal: 3, 5, 7 (sum = 15)
- Center element 5 was counted only once
- Total: 1 + 5 + 9 + 3 + 7 = 25
Solution Implementation
1class Solution:
2 def diagonalSum(self, mat: List[List[int]]) -> int:
3 """
4 Calculate the sum of elements on both diagonals of a square matrix.
5
6 Args:
7 mat: A square matrix represented as a list of lists
8
9 Returns:
10 The sum of all elements on the primary and secondary diagonals
11 """
12 total_sum = 0
13 matrix_size = len(mat)
14
15 # Iterate through each row of the matrix
16 for row_index, current_row in enumerate(mat):
17 # Calculate the column index for the secondary diagonal
18 # For row i, secondary diagonal element is at column (n - i - 1)
19 secondary_diagonal_col = matrix_size - row_index - 1
20
21 # Add the primary diagonal element (at position [row_index][row_index])
22 total_sum += current_row[row_index]
23
24 # Add the secondary diagonal element only if it's not the same as primary
25 # This happens when the matrix has odd dimensions and we're at the center
26 if secondary_diagonal_col != row_index:
27 total_sum += current_row[secondary_diagonal_col]
28
29 return total_sum
30
1class Solution {
2 public int diagonalSum(int[][] mat) {
3 int sum = 0;
4 int matrixSize = mat.length;
5
6 // Iterate through each row of the matrix
7 for (int row = 0; row < matrixSize; ++row) {
8 // Calculate the column index for the anti-diagonal element
9 int antiDiagonalCol = matrixSize - row - 1;
10
11 // Add the primary diagonal element at position [row][row]
12 sum += mat[row][row];
13
14 // Add the anti-diagonal element at position [row][antiDiagonalCol]
15 // Skip if it's the same element (center of odd-sized matrix)
16 if (row != antiDiagonalCol) {
17 sum += mat[row][antiDiagonalCol];
18 }
19 }
20
21 return sum;
22 }
23}
24
1class Solution {
2public:
3 int diagonalSum(vector<vector<int>>& mat) {
4 int sum = 0;
5 int matrixSize = mat.size();
6
7 // Iterate through each row of the matrix
8 for (int row = 0; row < matrixSize; ++row) {
9 // Calculate the column index for the secondary diagonal
10 int secondaryDiagonalCol = matrixSize - row - 1;
11
12 // Add the primary diagonal element at position [row][row]
13 sum += mat[row][row];
14
15 // Add the secondary diagonal element at position [row][secondaryDiagonalCol]
16 // Only add if it's not the same element as the primary diagonal
17 // (This happens when the matrix has odd dimensions and we're at the center)
18 if (row != secondaryDiagonalCol) {
19 sum += mat[row][secondaryDiagonalCol];
20 }
21 }
22
23 return sum;
24 }
25};
26
1/**
2 * Calculates the sum of elements on both diagonals of a square matrix.
3 * For the primary diagonal: elements where row index equals column index (i === i)
4 * For the secondary diagonal: elements where row index + column index equals n - 1
5 * If the matrix has odd dimensions, the center element is only counted once.
6 *
7 * @param mat - A square matrix represented as a 2D array of numbers
8 * @returns The sum of all elements on both diagonals
9 */
10function diagonalSum(mat: number[][]): number {
11 // Initialize the sum accumulator
12 let sum: number = 0;
13
14 // Get the dimension of the square matrix
15 const matrixSize: number = mat.length;
16
17 // Iterate through each row of the matrix
18 for (let rowIndex: number = 0; rowIndex < matrixSize; ++rowIndex) {
19 // Calculate the column index for the secondary diagonal
20 // When rowIndex is 0, secondaryDiagonalCol is n-1 (last column)
21 // When rowIndex is n-1, secondaryDiagonalCol is 0 (first column)
22 const secondaryDiagonalCol: number = matrixSize - rowIndex - 1;
23
24 // Add the primary diagonal element at position [rowIndex][rowIndex]
25 // Add the secondary diagonal element at position [rowIndex][secondaryDiagonalCol]
26 // If both indices are the same (center of odd-sized matrix), avoid double counting
27 sum += mat[rowIndex][rowIndex] + (rowIndex === secondaryDiagonalCol ? 0 : mat[rowIndex][secondaryDiagonalCol]);
28 }
29
30 return sum;
31}
32
Time and Space Complexity
The time complexity is O(n)
, where n
is the number of rows in the matrix. The algorithm iterates through each row exactly once using the enumerate function, performing constant-time operations (array access and arithmetic) for each row. Since there are n
rows and we visit each row once with O(1)
work per row, the total time complexity is O(n)
.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space regardless of the input size. The variables ans
, n
, i
, row
, and j
are the only additional space used, and these do not scale with the size of the input matrix. The enumerate iterator and the reference to each row do not create new data structures but rather reference existing elements in the input matrix.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Double-Counting the Center Element in Odd-Sized Matrices
The Pitfall: The most common mistake is forgetting to handle the center element in odd-sized matrices. When the matrix has odd dimensions (e.g., 3×3, 5×5), the center element belongs to both diagonals. A naive implementation might add this element twice:
# Incorrect approach - double counts center element
def diagonalSum_wrong(mat):
total = 0
n = len(mat)
for i in range(n):
total += mat[i][i] # Primary diagonal
total += mat[i][n-i-1] # Secondary diagonal - might double count!
return total
For a 3×3 matrix, when i = 1
, both mat[1][1]
(primary) and mat[1][3-1-1] = mat[1][1]
(secondary) refer to the same center element, causing it to be counted twice.
The Solution: Check if the current position on the primary diagonal is the same as the secondary diagonal position before adding:
def diagonalSum_correct(mat):
total = 0
n = len(mat)
for i in range(n):
total += mat[i][i] # Always add primary diagonal
if i != n - i - 1: # Only add secondary if different from primary
total += mat[i][n-i-1]
return total
2. Using Incorrect Index Calculation for Secondary Diagonal
The Pitfall:
Another frequent error is miscalculating the column index for the secondary diagonal. Some might incorrectly use formulas like n - i
or n - 1 - i
inconsistently:
# Incorrect - off by one error secondary_col = n - i # Should be n - i - 1 # This would try to access mat[0][n] which is out of bounds
The Solution:
Remember that for a matrix of size n
, the secondary diagonal element in row i
is at column n - i - 1
. This ensures:
- Row 0: column
n-1
(last column) - Row 1: column
n-2
(second to last) - Row
n-1
: column 0 (first column)
3. Attempting to Optimize with Set or Dictionary
The Pitfall: Some might try to "optimize" by collecting all diagonal positions first using sets to automatically handle duplicates:
# Overcomplicated and less efficient
def diagonalSum_overcomplicated(mat):
n = len(mat)
diagonal_positions = set()
# Collect all diagonal positions
for i in range(n):
diagonal_positions.add((i, i))
diagonal_positions.add((i, n-i-1))
# Sum the values
return sum(mat[r][c] for r, c in diagonal_positions)
While this works, it's actually less efficient due to the overhead of set operations and tuple creation.
The Solution: Stick with the simple linear traversal. The single-pass approach with a conditional check is both clearer and more efficient with O(n) time and O(1) space complexity.
Which algorithm should you use to find a node that is close to the root of the tree?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!