You are given a 2D matrix of size m x n
(with m
rows and n
columns). Your task is to return all elements of the matrix in a diagonal order, starting from the top-left element. The diagonal order follows a zigzag pattern: the first diagonal goes up-right, the next down-left, and so on, alternating directions for each diagonal.
For example, given the matrix:
[[ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ]]
The output should be: [1,2,4,7,5,3,6,8,9]
The main challenge is to traverse the matrix in a zigzag diagonal pattern, alternating directions for each diagonal. A brute-force solution might attempt to keep track of visited elements or simulate the direction changes manually, but this quickly becomes complex and error-prone.
Observing the problem, we can note that each diagonal in the matrix can be identified by the sum of its row and column indices (i.e., for element matrix[i][j]
, the diagonal number is i + j
). This insight helps us group elements by diagonals and then process each group in the correct order (reversing every other diagonal as needed).
Instead of using extra space to track visited elements, we can directly calculate the next position based on our current direction and the matrix boundaries, ensuring we visit each element once.
Here is a step-by-step breakdown of the optimal solution:
(i, j)
, the sum i + j
is constant for all elements in the same diagonal.
i + j
).
This approach is both simple and efficient, avoiding the need for explicit direction simulation or extra visited markers.
Consider the input matrix:
[[ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ]]
[1,2,4,7,5,3,6,8,9]
class Solution:
def findDiagonalOrder(self, matrix):
if not matrix or not matrix[0]:
return []
m, n = len(matrix), len(matrix[0])
diagonals = {}
for i in range(m):
for j in range(n):
if i + j not in diagonals:
diagonals[i + j] = []
diagonals[i + j].append(matrix[i][j])
result = []
for k in range(m + n - 1):
if k % 2 == 0:
result.extend(reversed(diagonals[k]))
else:
result.extend(diagonals[k])
return result
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return {};
int m = matrix.size(), n = matrix[0].size();
vector<vector<int>> diagonals(m + n - 1);
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
diagonals[i + j].push_back(matrix[i][j]);
}
}
vector<int> result;
for (int k = 0; k < m + n - 1; ++k) {
if (k % 2 == 0) {
result.insert(result.end(), diagonals[k].rbegin(), diagonals[k].rend());
} else {
result.insert(result.end(), diagonals[k].begin(), diagonals[k].end());
}
}
return result;
}
};
class Solution {
public int[] findDiagonalOrder(int[][] matrix) {
if (matrix == null || matrix.length == 0) return new int[0];
int m = matrix.length, n = matrix[0].length;
List<List<Integer>> diagonals = new ArrayList<>();
for (int i = 0; i < m + n - 1; ++i) diagonals.add(new ArrayList<>());
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
diagonals.get(i + j).add(matrix[i][j]);
}
}
int[] result = new int[m * n];
int idx = 0;
for (int k = 0; k < m + n - 1; ++k) {
List<Integer> diagonal = diagonals.get(k);
if (k % 2 == 0) {
for (int i = diagonal.size() - 1; i >= 0; --i)
result[idx++] = diagonal.get(i);
} else {
for (int num : diagonal)
result[idx++] = num;
}
}
return result;
}
}
var findDiagonalOrder = function(matrix) {
if (!matrix.length || !matrix[0].length) return [];
const m = matrix.length, n = matrix[0].length;
const diagonals = Array(m + n - 1).fill(0).map(() => []);
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
diagonals[i + j].push(matrix[i][j]);
}
}
const result = [];
for (let k = 0; k < m + n - 1; ++k) {
if (k % 2 === 0) {
result.push(...diagonals[k].reverse());
} else {
result.push(...diagonals[k]);
}
}
return result;
};
The solution is efficient and scales linearly with the size of the matrix.
The key insight for this problem is that elements on the same diagonal share the same sum of their indices. By grouping elements by this sum and reversing every other group, we can efficiently produce the required zigzag diagonal traversal. This approach is both simple and robust, avoiding complex direction simulation and ensuring every element is visited exactly once.
The result is an elegant, efficient, and easy-to-understand solution that leverages the properties of matrix indices.