Difference of Number of Distinct Values on Diagonals
MedPrompt
Given a 2D grid of size m x n, you should find the matrix answer of size m x n.
The cell answer[r][c] is calculated by looking at the diagonal values of the cell grid[r][c]:
- Let
leftAbove[r][c]be the number of distinct values on the diagonal to the left and above the cellgrid[r][c]not including the cellgrid[r][c]itself. - Let
rightBelow[r][c]be the number of distinct values on the diagonal to the right and below the cellgrid[r][c], not including the cellgrid[r][c]itself. - Then
answer[r][c] = |leftAbove[r][c] - rightBelow[r][c]|.
A matrix diagonal is a diagonal line of cells starting from some cell in either the topmost row or leftmost column and going in the bottom-right direction until the end of the matrix is reached.
- For example, in the below diagram the diagonal is highlighted using the cell with indices
(2, 3)colored gray:- Red-colored cells are left and above the cell.
- Blue-colored cells are right and below the cell.

Return the matrix answer.
Example 1:
Input: grid = [[1,2,3],[3,1,5],[3,2,1]]
Output: Output: [[1,1,0],[1,0,1],[0,1,1]]
Explanation:
To calculate the answer cells:
| answer | left-above elements | leftAbove | right-below elements | rightBelow | |leftAbove - rightBelow| |
|---|---|---|---|---|---|
| [0][0] | [] | 0 | [grid[1][1], grid[2][2]] | |{1, 1}| = 1 | 1 |
| [0][1] | [] | 0 | [grid[1][2]] | |{5}| = 1 | 1 |
| [0][2] | [] | 0 | [] | 0 | 0 |
| [1][0] | [] | 0 | [grid[2][1]] | |{2}| = 1 | 1 |
| [1][1] | [grid[0][0]] | |{1}| = 1 | [grid[2][2]] | |{1}| = 1 | 0 |
| [1][2] | [grid[0][1]] | |{2}| = 1 | [] | 0 | 1 |
| [2][0] | [] | 0 | [] | 0 | 0 |
| [2][1] | [grid[1][0]] | |{3}| = 1 | [] | 0 | 1 |
| [2][2] | [grid[0][0], grid[1][1]] | |{1, 1}| = 1 | [] | 0 | 1 |
Example 2:
Input: grid = [[1]]
Output: Output: [[0]]
Constraints:
m == grid.lengthn == grid[i].length1 <= m, n, grid[i][j] <= 50
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. For each cell (r, c) in the grid, it independently calculates the number of distinct values in the top-left diagonal and the bottom-right diagonal.
Algorithm
- Initialize an
m x nmatrixanswer. - For each row
rfrom0tom-1: - For each column
cfrom0ton-1: -
// Calculate leftAbove[r][c] -
Create a `HashSet` `topLeftSet`. -
Iterate with `i = r-1`, `j = c-1` as long as `i >= 0` and `j >= 0`: -
Add `grid[i][j]` to `topLeftSet`. -
Decrement `i` and `j`. -
`leftAbove = topLeftSet.size()`. - // Calculate rightBelow[r][c]
- Create a
HashSetbottomRightSet. - Iterate with
i = r+1,j = c+1as long asi < mandj < n: -
Add `grid[i][j]` to `bottomRightSet`. -
Increment `i` and `j`. rightBelow = bottomRightSet.size().- // Store the result
answer[r][c] = Math.abs(leftAbove - rightBelow).- Return
answer.
Walkthrough
We iterate through every cell (r, c) of the grid. For each cell, we perform two separate traversals:
- Top-Left Diagonal (
leftAbove): We traverse from(r-1, c-1)up towards the grid boundaries. We use aHashSetto collect all the values encountered, and its size gives us the count of distinct elements. - Bottom-Right Diagonal (
rightBelow): We traverse from(r+1, c+1)down towards the grid boundaries. Similarly, we use anotherHashSetto find the count of distinct elements.
The value for answer[r][c] is then the absolute difference between these two counts. This process is repeated for all m * n cells.
import java.util.HashSet;import java.util.Set; class Solution { public int[][] differenceOfDistinctValues(int[][] grid) { int m = grid.length; int n = grid[0].length; int[][] answer = new int[m][n]; for (int r = 0; r < m; r++) { for (int c = 0; c < n; c++) { // Calculate leftAbove Set<Integer> topLeftSet = new HashSet<>(); int i = r - 1; int j = c - 1; while (i >= 0 && j >= 0) { topLeftSet.add(grid[i][j]); i--; j--; } int leftAbove = topLeftSet.size(); // Calculate rightBelow Set<Integer> bottomRightSet = new HashSet<>(); i = r + 1; j = c + 1; while (i < m && j < n) { bottomRightSet.add(grid[i][j]); i++; j++; } int rightBelow = bottomRightSet.size(); answer[r][c] = Math.abs(leftAbove - rightBelow); } } return answer; }}Complexity
Time
O(m * n * min(m, n)). For each of the `m * n` cells, we traverse its top-left and bottom-right diagonals. The maximum length of a diagonal is `min(m, n)`, leading to this complexity.
Space
O(min(m, n)). For each cell, we create two `HashSet`s. The maximum size of a set is bounded by the length of the diagonal, which is `min(m, n)`. This is the auxiliary space, excluding the `O(m * n)` space for the output matrix.
Trade-offs
Pros
Simple to understand and implement.
Directly follows the problem definition.
Cons
Inefficient due to redundant calculations. The distinct counts for overlapping diagonal segments are re-calculated multiple times for different cells.
This approach improves upon the brute-force method by processing the grid one diagonal at a time. By traversing each diagonal twice (once forward and once backward), we can efficiently calculate leftAbove and rightBelow for all cells on that diagonal without redundant computations.
Algorithm
- Initialize an
m x nmatrixanswer. - // Process diagonals starting from the top row
- For each column
jfrom0ton-1: - // Forward pass for leftAbove
- Create a set
distinct_elements. - Iterate along the diagonal starting at
(0, j): forr, c = 0, j,1, j+1, ... -
`answer[r][c] = distinct_elements.size()`. -
Add `grid[r][c]` to `distinct_elements`. - // Backward pass for rightBelow
- Clear
distinct_elements. - Iterate backwards along the same diagonal:
rightBelowCount = distinct_elements.size().answer[r][c] = Math.abs(answer[r][c] - rightBelowCount).- Add
grid[r][c]todistinct_elements. - // Process diagonals starting from the left column (excluding the one at (0,0) already processed)
- For each row
ifrom1tom-1: - // Repeat steps 4-14 for the diagonal starting at
(i, 0). - Return
answer.
Walkthrough
The key observation is that for any two cells on the same diagonal, their leftAbove and rightBelow sets are related. For a cell (r, c), the set of distinct elements for leftAbove of (r+1, c+1) is simply the set for leftAbove of (r, c) with the element grid[r][c] added.
We can iterate through all m + n - 1 diagonals. Diagonals are identified by their starting cell, which is either in the first row (0, j) or the first column (i, 0).
For each diagonal:
- Forward Pass (for
leftAbove): We traverse the diagonal from top-left to bottom-right. We maintain a set of unique elements seen so far. For each cell(r, c), the size of this set givesleftAbove[r][c]. We store this value temporarily in ouranswermatrix. After processing the cell, we addgrid[r][c]to the set. - Backward Pass (for
rightBelow): We traverse the same diagonal from bottom-right to top-left. We again maintain a set of unique elements. For each cell(r, c), the size of this set givesrightBelow[r][c]. We then calculate the final answer for this cell:answer[r][c] = |answer[r][c] - rightBelow[r][c]|. After processing, we addgrid[r][c]to the set for the next iteration (the cell to its top-left).
Since the values in the grid are small (1-50), we can use a frequency array of size 51 instead of a HashSet for a slight performance gain, making set operations true O(1).
import java.util.HashSet;import java.util.Set; class Solution { public int[][] differenceOfDistinctValues(int[][] grid) { int m = grid.length; int n = grid[0].length; int[][] answer = new int[m][n]; // Process diagonals starting from the top row for (int j = 0; j < n; j++) { processDiagonal(grid, answer, 0, j, m, n); } // Process diagonals starting from the left column (skip (0,0) as it's covered) for (int i = 1; i < m; i++) { processDiagonal(grid, answer, i, 0, m, n); } return answer; } private void processDiagonal(int[][] grid, int[][] answer, int startR, int startC, int m, int n) { // Forward pass for leftAbove Set<Integer> distinctElements = new HashSet<>(); int r = startR; int c = startC; while (r < m && c < n) { answer[r][c] = distinctElements.size(); distinctElements.add(grid[r][c]); r++; c++; } // Backward pass for rightBelow distinctElements.clear(); r--; // Start from the last element of the diagonal c--; while (r >= startR && c >= startC) { int rightBelowCount = distinctElements.size(); answer[r][c] = Math.abs(answer[r][c] - rightBelowCount); distinctElements.add(grid[r][c]); r--; c--; } }}Complexity
Time
O(m * n). Each cell in the grid is visited exactly twice: once during a forward pass and once during a backward pass on its diagonal. The operations inside the loops (set insertion and size check) take constant time on average.
Space
O(min(m, n)). The auxiliary space required is for the `HashSet`, which at most stores all elements on the longest diagonal. The length of the longest diagonal is `min(m, n)`. Given the constraints on grid values, a frequency array of size 51 could be used, making the auxiliary space `O(1)` (constant). The `O(m*n)` space for the output matrix is not counted as auxiliary.
Trade-offs
Pros
Highly efficient, with optimal time complexity.
Avoids redundant computations by processing each diagonal cohesively.
Cons
The logic is slightly more complex than the brute-force approach, involving separate handling of diagonals and two passes.
Solutions
Solution
class Solution {public int[][] differenceOfDistinctValues(int[][] grid) { int m = grid.length, n = grid[0].length; int[][] ans = new int[m][n]; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { int x = i, y = j; Set<Integer> s = new HashSet<>(); while (x > 0 && y > 0) { s.add(grid[--x][--y]); } int tl = s.size(); x = i; y = j; s.clear(); while (x < m - 1 && y < n - 1) { s.add(grid[++x][++y]); } int br = s.size(); ans[i][j] = Math.abs(tl - br); } } return ans; }}class Solution {public: vector<vector<int>> differenceOfDistinctValues(vector<vector<int>> &grid) { int m = grid.size(), n = grid[0].size(); vector<vector<int>> ans(m, vector<int>(n)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { int x = i, y = j; unordered_set<int> s; while (x > 0 && y > 0) { s.insert(grid[--x][--y]); } int tl = s.size(); x = i; y = j; s.clear(); while (x < m - 1 && y < n - 1) { s.insert(grid[++x][++y]); } int br = s.size(); ans[i][j] = abs(tl - br); } } return ans; }};class Solution: def differenceOfDistinctValues(self, grid: List[List[int]]) -> List[List[int]]: m, n = len(grid), len(grid[0]) ans = [[0] * n for _ in range(m)] for i in range(m): for j in range(n): x, y = i, j s = set() while x and y: x, y = x - 1, y - 1 s . add(grid[x][y]) tl = len(s) x, y = i, j s = set() while x + 1 < m and y + 1 < n: x, y = x + 1, y + 1 s . add(grid[x][y]) br = len(s) ans[i][j] = abs(tl - br) return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.