leetcode
leetcode 2751 ~ 2800
在矩阵上写出字母 Y 所需的最少操作次数

在矩阵上写出字母 Y 所需的最少操作次数

难度:

标签:

题目描述

You are given a 0-indexed n x n grid where n is odd, and grid[r][c] is 0, 1, or 2.

We say that a cell belongs to the Letter Y if it belongs to one of the following:

  • The diagonal starting at the top-left cell and ending at the center cell of the grid.
  • The diagonal starting at the top-right cell and ending at the center cell of the grid.
  • The vertical line starting at the center cell and ending at the bottom border of the grid.

The Letter Y is written on the grid if and only if:

  • All values at cells belonging to the Y are equal.
  • All values at cells not belonging to the Y are equal.
  • The values at cells belonging to the Y are different from the values at cells not belonging to the Y.

Return the minimum number of operations needed to write the letter Y on the grid given that in one operation you can change the value at any cell to 0, 1, or 2.

 

Example 1:

Input: grid = [[1,2,2],[1,1,0],[0,1,0]]
Output: 3
Explanation: We can write Y on the grid by applying the changes highlighted in blue in the image above. After the operations, all cells that belong to Y, denoted in bold, have the same value of 1 while those that do not belong to Y are equal to 0.
It can be shown that 3 is the minimum number of operations needed to write Y on the grid.

Example 2:

Input: grid = [[0,1,0,1,0],[2,1,0,1,2],[2,2,2,0,1],[2,2,2,2,2],[2,1,2,2,2]]
Output: 12
Explanation: We can write Y on the grid by applying the changes highlighted in blue in the image above. After the operations, all cells that belong to Y, denoted in bold, have the same value of 0 while those that do not belong to Y are equal to 2. 
It can be shown that 12 is the minimum number of operations needed to write Y on the grid.

 

Constraints:

  • 3 <= n <= 49
  • n == grid.length == grid[i].length
  • 0 <= grid[i][j] <= 2
  • n is odd.

代码结果

运行时间: 43 ms, 内存: 16.2 MB


/*
 * 思路:
 * 1. 找出矩阵的中心点。
 * 2. 使用流处理来记录Y字母形状所需的坐标。
 * 3. 计算当前属于Y形状的单元格和非Y形状的单元格的值。
 * 4. 计算将这些单元格转换为目标值所需的操作次数。
 * 5. 返回最少的操作次数。
 */
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {
    public int minOperations(int[][] grid) {
        int n = grid.length;
        int center = n / 2;

        List<int[]> yCells = IntStream.range(0, center + 1)
                .flatMap(i -> Stream.of(new int[]{i, i}, new int[]{i, n - 1 - i}))
                .collect(Collectors.toList());
        yCells.addAll(IntStream.range(center, n).mapToObj(i -> new int[]{i, center}).collect(Collectors.toList()));

        Set<Integer> yValues = yCells.stream().map(cell -> grid[cell[0]][cell[1]]).collect(Collectors.toSet());
        Set<Integer> nonYValues = IntStream.range(0, n).boxed()
                .flatMap(i -> IntStream.range(0, n).mapToObj(j -> new int[]{i, j}))
                .filter(cell -> !yCells.contains(cell))
                .map(cell -> grid[cell[0]][cell[1]]).collect(Collectors.toSet());

        return yValues.stream().flatMapToInt(yValue -> nonYValues.stream()
                .filter(nonYValue -> yValue != nonYValue)
                .mapToInt(nonYValue -> (int) yCells.stream().filter(cell -> grid[cell[0]][cell[1]] != yValue).count() +
                        (int) IntStream.range(0, n).boxed()
                                .flatMap(i -> IntStream.range(0, n).mapToObj(j -> new int[]{i, j}))
                                .filter(cell -> !yCells.contains(cell) && grid[cell[0]][cell[1]] != nonYValue)
                                .count())).min().orElse(Integer.MAX_VALUE);
    }
}

解释

方法:

此题的解法是通过统计属于Y形的单元格和非Y形的单元格中0、1、2的出现次数,然后尝试所有可能的值组合来最小化变换次数。首先使用两个计数器cnt1和cnt2分别统计属于Y的单元格和不属于Y的单元格中0、1、2的出现次数。接着,对于每种可能的Y值(0、1、2)和非Y值(也是0、1、2),当Y值不等于非Y值时,计算不需要变化的单元格数量(即已经为目标值的单元格数量)。最后,从总单元格数中减去这个最大的不需要变化的单元格数量,得到最小的操作次数。

时间复杂度:

O(n^2)

空间复杂度:

O(1)

代码细节讲解

🦆
如何确定哪些单元格属于Y形的一部分以及哪些不属于?代码中具体的判断逻辑是什么?
在代码中,Y形部分的确定基于矩阵的对称性和中心线。具体逻辑如下:对于矩阵的上半部分(即索引从0到m-1的行),属于Y形的单元格包括左右两条对角线上的单元格。这通过判断索引关系i和n-1-i来实现,其中i是行的索引,n是矩阵的大小。在矩阵的下半部分(即索引从m到n-1的行),属于Y形的单元格仅包括中心竖线上的单元格,即列索引为m的单元格。不属于Y形的单元格则是除了上述Y形单元格以外的所有单元格。
🦆
在计算操作次数时,为什么要尝试所有可能的Y值和非Y值组合,而不是直接选取出现次数最多的值作为目标值?
尝试所有可能的Y值和非Y值组合是为了确保找到真正的最小操作次数。如果仅选择出现次数最多的值作为目标值,可能会忽略不同值间转换的逻辑关系,导致实际操作次数并非最小。例如,如果Y形区域内出现次数最多的是1,而非Y形区域内出现次数最多的也是1,按照简单的最多次数策略将两者都设置为1,这会忽略Y形与非Y形区域应有不同的数值要求。因此,通过遍历所有可能的值组合,确保Y形与非Y形区域的值不同,从而找到真正的最少改变次数。
🦆
对于中心单元格,它似乎在代码中被重复计算了两次(一次在上半部分,一次在下半部分的垂直线),这样处理是否正确?
这种处理是不正确的,因为中心单元格只应计算一次。在代码中,中心单元格出现在矩阵的上半部分的最后一行以及下半部分的第一行的中心位置。这个重复计算可能会导致对Y形区域内的某些值的计数不准确,从而影响最终的操作次数计算。正确的做法应该是确保中心单元格只在其中一个部分被计算,通常选择在下半部分计算一次即可。

相关问题