leetcode
leetcode 1401 ~ 1450
奇怪的打印机 II

奇怪的打印机 II

难度:

标签:

题目描述

给你一个奇怪的打印机,它有如下两个特殊的打印规则:

  • 每一次操作时,打印机会用同一种颜色打印一个矩形的形状,每次打印会覆盖矩形对应格子里原本的颜色。
  • 一旦矩形根据上面的规则使用了一种颜色,那么 相同的颜色不能再被使用 

给你一个初始没有颜色的 m x n 的矩形 targetGrid ,其中 targetGrid[row][col] 是位置 (row, col) 的颜色。

如果你能按照上述规则打印出矩形 targetGrid ,请你返回 true ,否则返回 false 。

 

示例 1:

输入:targetGrid = [[1,1,1,1],[1,2,2,1],[1,2,2,1],[1,1,1,1]]
输出:true

示例 2:

输入:targetGrid = [[1,1,1,1],[1,1,3,3],[1,1,3,4],[5,5,1,4]]
输出:true

示例 3:

输入:targetGrid = [[1,2,1],[2,1,2],[1,2,1]]
输出:false
解释:没有办法得到 targetGrid ,因为每一轮操作使用的颜色互不相同。

示例 4:

输入:targetGrid = [[1,1,1],[3,1,3]]
输出:false

 

提示:

  • m == targetGrid.length
  • n == targetGrid[i].length
  • 1 <= m, n <= 60
  • 1 <= targetGrid[row][col] <= 60

代码结果

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


// Solution in Java using Streams
// Approach: Similar to the Java solution, we use a map to track bounds for each color and then validate those bounds.
// However, we will use streams for data processing where possible.

import java.util.*;
import java.util.stream.*;

public class StrangePrinterStream {
    public boolean isPrintable(int[][] targetGrid) {
        int m = targetGrid.length;
        int n = targetGrid[0].length;
        Map<Integer, int[]> colorBounds = new HashMap<>();

        // Determine bounds for each color using streams
        IntStream.range(0, m).forEach(i ->
            IntStream.range(0, n).forEach(j -> {
                int color = targetGrid[i][j];
                colorBounds.compute(color, (k, v) -> {
                    if (v == null) return new int[]{i, i, j, j};
                    v[0] = Math.min(v[0], i);
                    v[1] = Math.max(v[1], i);
                    v[2] = Math.min(v[2], j);
                    v[3] = Math.max(v[3], j);
                    return v;
                });
            })
        );

        // Verify if each color's rectangle is valid
        return colorBounds.entrySet().stream().allMatch(entry -> {
            int color = entry.getKey();
            int[] bounds = entry.getValue();
            return IntStream.range(bounds[0], bounds[1] + 1).allMatch(i ->
                IntStream.range(bounds[2], bounds[3] + 1).allMatch(j ->
                    targetGrid[i][j] == color
                )
            );
        });
    }

    public static void main(String[] args) {
        StrangePrinterStream sp = new StrangePrinterStream();
        int[][] targetGrid1 = {
            {1, 1, 1, 1},
            {1, 2, 2, 1},
            {1, 2, 2, 1},
            {1, 1, 1, 1}
        };
        System.out.println(sp.isPrintable(targetGrid1)); // true

        int[][] targetGrid2 = {
            {1, 1, 1, 1},
            {1, 1, 3, 3},
            {1, 1, 3, 4},
            {5, 5, 1, 4}
        };
        System.out.println(sp.isPrintable(targetGrid2)); // true

        int[][] targetGrid3 = {
            {1, 2, 1},
            {2, 1, 2},
            {1, 2, 1}
        };
        System.out.println(sp.isPrintable(targetGrid3)); // false
    }
}

解释

方法:

此题解采用了模拟打印机打印过程的方法。首先,使用一个字典记录每种颜色最初和最终出现的行和列(形成一个边界框),这意味着如果颜色c在一个矩形区域内完整存在,则理论上可以通过一次打印操作实现该颜色。之后,对每个颜色尝试执行打印操作:检查其边界框内是否所有颜色都能匹配目标或已被覆盖(值为-1)。如果可以,那么该颜色对应的区域就被设置为-1以表示该区域已被完全打印覆盖。该过程反复进行,直到没有颜色可以成功打印(返回false)或所有颜色都被打印完(返回true)。

时间复杂度:

O(C * m * n)

空间复杂度:

O(C)

代码细节讲解

🦆
为什么在题解中使用字典来记录每种颜色的边界框而不是其他数据结构,如数组或列表?
在题解中使用字典来记录每种颜色的边界框是因为字典提供了更高效的颜色到其边界框映射的访问方式。使用字典,可以直接通过颜色值作为键快速查找和更新对应颜色的边界框信息。如果使用数组或列表,则可能需要额外的步骤来确定哪个索引或位置对应哪个颜色,这会增加复杂性和可能的计算开销。此外,颜色的数量和具体值可能是不连续的,使用字典可以更灵活地处理这种情况。
🦆
在题解的打印检查函数`can_be_grid`中,为什么判断条件包括了`-1`?这代表了什么意义?
在打印检查函数`can_be_grid`中,判断条件包括`-1`是因为`-1`代表了该区域已经被打印处理。这意味着当我们检查一个颜色的边界框是否可以通过一次打印操作成功覆盖时,只需关注尚未打印的区域(即未标记为`-1`的区域)和当前颜色。包含`-1`作为有效条件允许算法忽视已经成功打印过的区域,从而只关注剩余未处理的部分。
🦆
题解中提到,一旦可以打印某种颜色,就将该区域设置为-1。这样做有可能影响后续颜色的判断吗?如何避免或解决这种潜在问题?
将区域设置为-1表示该区域已被打印覆盖,确实有可能影响后续的颜色判断,尤其是如果多个颜色的打印区域有重叠时。为了避免这种问题,算法中在每次成功打印一个颜色并将对应区域设置为-1后,会从记录颜色边界的字典中移除该颜色。这样,在后续迭代中,已处理的颜色不会再次参与判断,从而避免了重叠后的错误覆盖或干扰。
🦆
在题解的逻辑中,如果在某一轮迭代中没有任何颜色被成功打印,就直接返回`false`。这种做法是否有可能漏掉某些特殊情况,导致错误的判断?
题解中这种做法是基于假设:如果在任何迭代轮次中发现没有颜色可以被成功打印,这表明存在至少一个颜色的边界框内包含了其他不可移除的颜色,导致无法继续进行打印。这种情况意味着无法通过有限次的打印操作达到目标,因此返回`false`是合理的。虽然这是一个较为严格的判断,但按照题目逻辑和打印机操作的模拟,这种处理是符合实际情况的,不会漏掉特殊情况。

相关问题