leetcode
leetcode 2301 ~ 2350
对角线上不同值的数量差

对角线上不同值的数量差

难度:

标签:

题目描述

Given a 0-indexed 2D grid of size m x n, you should find the matrix answer of size m x n.

The value of each cell (r, c) of the matrix answer is calculated in the following way:

  • Let topLeft[r][c] be the number of distinct values in the top-left diagonal of the cell (r, c) in the matrix grid.
  • Let bottomRight[r][c] be the number of distinct values in the bottom-right diagonal of the cell (r, c) in the matrix grid.

Then answer[r][c] = |topLeft[r][c] - bottomRight[r][c]|.

Return the matrix answer.

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 reaching the matrix's end.

A cell (r1, c1) belongs to the top-left diagonal of the cell (r, c), if both belong to the same diagonal and r1 < r. Similarly is defined bottom-right diagonal.

 

Example 1:


Input: grid = [[1,2,3],[3,1,5],[3,2,1]]
Output: [[1,1,0],[1,0,1],[0,1,1]]
Explanation: The 1st diagram denotes the initial grid. 
The 2nd diagram denotes a grid for cell (0,0), where blue-colored cells are cells on its bottom-right diagonal.
The 3rd diagram denotes a grid for cell (1,2), where red-colored cells are cells on its top-left diagonal.
The 4th diagram denotes a grid for cell (1,1), where blue-colored cells are cells on its bottom-right diagonal and red-colored cells are cells on its top-left diagonal.
- The cell (0,0) contains [1,1] on its bottom-right diagonal and [] on its top-left diagonal. The answer is |1 - 0| = 1.
- The cell (1,2) contains [] on its bottom-right diagonal and [2] on its top-left diagonal. The answer is |0 - 1| = 1.
- The cell (1,1) contains [1] on its bottom-right diagonal and [1] on its top-left diagonal. The answer is |1 - 1| = 0.
The answers of other cells are similarly calculated.

Example 2:

Input: grid = [[1]]
Output: [[0]]
Explanation: - The cell (0,0) contains [] on its bottom-right diagonal and [] on its top-left diagonal. The answer is |0 - 0| = 0.

 

Constraints:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n, grid[i][j] <= 50

代码结果

运行时间: 51 ms, 内存: 16.3 MB


/**
 * Problem description:
 * Given a 2D matrix `grid` of size m x n, return a matrix `answer` of the same size.
 * For each cell (r, c) in `answer`, the value is defined as the absolute difference between
 * the number of distinct values in the top-left diagonal and the bottom-right diagonal in `grid`.
 *
 * Solution (using Java Streams):
 * 1. Stream through each cell and calculate the distinct values in the top-left and bottom-right diagonals.
 * 2. Store the results in the `answer` matrix by taking the absolute difference.
 */
import java.util.*;
import java.util.stream.*;

public class Solution {
    public int[][] diagonalDifference(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] answer = new int[m][n];

        IntStream.range(0, m).forEach(r ->
            IntStream.range(0, n).forEach(c -> {
                // Calculate distinct count in top-left diagonal
                long topLeft = IntStream.iterate(r, i -> i - 1)
                    .limit(Math.min(r, c) + 1)
                    .mapToObj(i -> grid[i][c - (r - i)])
                    .distinct()
                    .count();

                // Calculate distinct count in bottom-right diagonal
                long bottomRight = IntStream.iterate(r, i -> i + 1)
                    .limit(Math.min(m - r, n - c))
                    .mapToObj(i -> grid[i][c + (i - r)])
                    .distinct()
                    .count();

                // Calculate the answer for cell (r, c)
                answer[r][c] = (int) Math.abs(topLeft - bottomRight);
            })
        );

        return answer;
    }
}

解释

方法:

此题解方法通过遍历矩阵中的所有对角线来计算左上角和右下角的对角线上的不同值数量。首先,使用四个独立的循环来分别处理矩阵的四个边界开始的对角线:首先是从上边界开始的左上到右下的对角线(两个循环),接着是从右边界和底边界开始的右下到左上的对角线(两个循环)。每个循环中使用一个集合来存储遍历过程中遇到的不同的值,并在每个单元格更新answer矩阵中的对应值。最后,根据左上和右下的值计算其差的绝对值。

时间复杂度:

O((m + n) * min(m, n))

空间复杂度:

O(min(m, n))

代码细节讲解

🦆
在遍历并计算每个对角线的不同值时,为什么选择使用集合而不是其他数据结构?
在处理对角线不同值的计算时,集合(Set)提供了一种快速有效的方式来确保值的唯一性,即自动处理重复值。集合的主要操作包括添加元素和检查元素是否存在,这两种操作通常都能在平均常数时间内完成,这使得它非常适合于此类问题,其中需要频繁地检查和添加不同的元素。相比之下,如果使用列表(List)或数组(Array),则每次添加新元素时都需先遍历已有元素以避免重复,这会导致时间复杂度显著增加。
🦆
对于每个单元格,您如何确保在计算`topLeft[r][c]`和`bottomRight[r][c]`时不会出现重复计数的问题?
题解中通过分别维护两个独立的集合来处理从左上到右下和从右下到左上的对角线。这两个集合在遍历时各自独立,确保了在计算每个方向上的对角线时,都是从新的集合开始,避免了重复计数的问题。同时,在计算结果矩阵`ans[r][c]`时使用绝对值来处理两个方向上不同值的数量之差,这进一步确保了不会由于遍历顺序或重复元素影响最终结果的正确性。
🦆
在对角线遍历的过程中,如果矩阵的行数和列数差异较大,这种方法的效率如何,是否会造成某些行或列的重复遍历?
在矩阵行数和列数差异较大的情况下,方法依然保持效率,因为每次遍历都是沿着单独的对角线从某一边界到另一边界。虽然某些对角线可能较短(特别是当接近矩阵的角落时),但每个元素仍然只被访问一次,不会造成重复遍历。此外,对于每个方向的对角线,遍历是从边界开始,直到另一边界结束,有效地利用了每个元素。
🦆
在更新答案矩阵`ans`时,为什么选择在遍历每个对角线的过程中更新`ans`的值,而不是单独计算完所有对角线后再统一计算`ans`的值?
这种方法允许在遍历对角线时即时更新答案矩阵,这样可以边计算边更新,避免了在所有数据收集完毕后再进行一次整体的复杂计算,这样可以降低时间复杂度和空间复杂度。实时更新结果也使得代码结构更简洁,逻辑更清晰,易于理解和维护。此外,这种方法避免了可能的错误和复杂性,因为所有必要的信息在访问某个单元格时都是最新的,并立即应用到答案矩阵中。

相关问题