Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
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]:
leftAbove[r][c] be the number of distinct values on the diagonal to the left and above the cell grid[r][c] not including the cell grid[r][c] itself.rightBelow[r][c] be the number of distinct values on the diagonal to the right and below the cell grid[r][c], not including the cell grid[r][c] itself.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.
(2, 3) colored gray:
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] <= 50Problem summary: 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 cell grid[r][c] not including the cell grid[r][c] itself. Let rightBelow[r][c] be the number of distinct values on the diagonal to the right and below the cell grid[r][c], not including the cell grid[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.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
[[1,2,3],[3,1,5],[3,2,1]]
[[1]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2711: Difference of Number of Distinct Values on Diagonals
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;
}
}
// Accepted solution for LeetCode #2711: Difference of Number of Distinct Values on Diagonals
func differenceOfDistinctValues(grid [][]int) [][]int {
m, n := len(grid), len(grid[0])
ans := make([][]int, m)
for i := range grid {
ans[i] = make([]int, n)
for j := range grid[i] {
x, y := i, j
s := map[int]bool{}
for x > 0 && y > 0 {
x, y = x-1, y-1
s[grid[x][y]] = true
}
tl := len(s)
x, y = i, j
s = map[int]bool{}
for x+1 < m && y+1 < n {
x, y = x+1, y+1
s[grid[x][y]] = true
}
br := len(s)
ans[i][j] = abs(tl - br)
}
}
return ans
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
# Accepted solution for LeetCode #2711: Difference of Number of Distinct Values on Diagonals
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 ans
// Accepted solution for LeetCode #2711: Difference of Number of Distinct Values on Diagonals
/**
* [2711] Difference of Number of Distinct Values on Diagonals
*/
pub struct Solution {}
// submission codes start here
use std::collections::HashMap;
use std::collections::HashSet;
impl Solution {
pub fn difference_of_distinct_values(grid: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
let m = grid.len();
let n = grid[0].len();
let mut result = vec![vec![0; n]; m];
Self::iterate_diagonal(&grid, &mut result, (0..m).rev().map(|i| (i, 0)));
Self::iterate_diagonal(&grid, &mut result, (0..n).rev().map(|i| (0, i)));
result
}
fn iterate_diagonal<T>(grid: &Vec<Vec<i32>>, result: &mut Vec<Vec<i32>>, iter: T)
where
T: Iterator<Item = (usize, usize)>,
{
let m = grid.len();
let n = grid[0].len();
let max_length = m.min(n);
let mut length = 1;
for (i, j) in iter {
let mut left_set = HashSet::with_capacity(length);
// 右下对角线因为涉及到添加和删除
// 使用哈希表存储对应数字的出现次数
let mut right_set = HashMap::with_capacity(length);
// 首先遍历右下
let (mut x, mut y) = (i + 1, j + 1);
for _ in 1..length {
let entry = right_set.entry(grid[x][y]).or_insert(0);
*entry += 1;
x += 1;
y += 1;
}
// 然后开始遍历
let (mut x, mut y) = (i, j);
for k in 0..length {
// 删除右下对角线
if k != 0 {
let entry = right_set.get_mut(&grid[x][y]).unwrap();
*entry -= 1;
if *entry == 0 {
right_set.remove(&grid[x][y]);
}
}
result[x][y] = left_set.len().abs_diff(right_set.len()) as i32;
// 插入左上对角线
left_set.insert(grid[x][y]);
x += 1;
y += 1;
}
length = max_length.min(length + 1);
}
}
}
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_2711() {
assert_eq!(
vec![vec![1, 1, 0], vec![1, 0, 1], vec![0, 1, 1]],
Solution::difference_of_distinct_values(vec![
vec![1, 2, 3],
vec![3, 1, 5],
vec![3, 2, 1]
])
);
assert_eq!(
vec![vec![0]],
Solution::difference_of_distinct_values(vec![vec![1]])
);
}
}
// Accepted solution for LeetCode #2711: Difference of Number of Distinct Values on Diagonals
function differenceOfDistinctValues(grid: number[][]): number[][] {
const m = grid.length;
const n = grid[0].length;
const ans: number[][] = Array(m)
.fill(0)
.map(() => Array(n).fill(0));
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
let [x, y] = [i, j];
const s = new Set<number>();
while (x && y) {
s.add(grid[--x][--y]);
}
const tl = s.size;
[x, y] = [i, j];
s.clear();
while (x + 1 < m && y + 1 < n) {
s.add(grid[++x][++y]);
}
const br = s.size;
ans[i][j] = Math.abs(tl - br);
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.