Skip to content

1591. Strange Printer II 👍

  • Time: $O(60 \cdot mn)$
  • Space: $O(mn)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
enum class State { kInit, kVisiting, kVisited };

class Solution {
 public:
  bool isPrintable(vector<vector<int>>& targetGrid) {
    constexpr int kMaxColor = 60;
    const int m = targetGrid.size();
    const int n = targetGrid[0].size();
    // graph[u] := {v1, v2} means v1 and v2 cover u
    vector<unordered_set<int>> graph(kMaxColor + 1);

    for (int color = 1; color <= kMaxColor; ++color) {
      // Get the rectangle of the current color.
      int minI = m;
      int minJ = n;
      int maxI = -1;
      int maxJ = -1;
      for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j)
          if (targetGrid[i][j] == color) {
            minI = min(minI, i);
            minJ = min(minJ, j);
            maxI = max(maxI, i);
            maxJ = max(maxJ, j);
          }
      // Add any color covering the current as the children.
      for (int i = minI; i <= maxI; ++i)
        for (int j = minJ; j <= maxJ; ++j)
          if (targetGrid[i][j] != color)
            graph[color].insert(targetGrid[i][j]);
    }

    vector<State> states(kMaxColor + 1);

    for (int color = 1; color <= kMaxColor; ++color)
      if (hasCycle(graph, color, states))
        return false;

    return true;
  }

 private:
  bool hasCycle(const vector<unordered_set<int>>& graph, int u,
                vector<State>& states) {
    if (states[u] == State::kVisiting)
      return true;
    if (states[u] == State::kVisited)
      return false;

    states[u] = State::kVisiting;
    for (const int v : graph[u])
      if (hasCycle(graph, v, states))
        return true;
    states[u] = State::kVisited;

    return false;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
enum State { kInit, kVisiting, kVisited }

class Solution {
  public boolean isPrintable(int[][] targetGrid) {
    final int kMaxColor = 60;
    final int m = targetGrid.length;
    final int n = targetGrid[0].length;
    // graph[u] := {v1, v2} means v1 and v2 cover u
    Set<Integer>[] graph = new HashSet[kMaxColor + 1];

    for (int color = 1; color <= kMaxColor; ++color) {
      // Get the rectangle of the current color.
      int minI = m;
      int minJ = n;
      int maxI = -1;
      int maxJ = -1;
      for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j)
          if (targetGrid[i][j] == color) {
            minI = Math.min(minI, i);
            minJ = Math.min(minJ, j);
            maxI = Math.max(maxI, i);
            maxJ = Math.max(maxJ, j);
          }
      // Add any color covering the current as the children.
      graph[color] = new HashSet<>();
      for (int i = minI; i <= maxI; ++i)
        for (int j = minJ; j <= maxJ; ++j)
          if (targetGrid[i][j] != color) {
            graph[color].add(targetGrid[i][j]);
          }
    }

    State[] states = new State[kMaxColor + 1];

    for (int color = 1; color <= kMaxColor; ++color)
      if (hasCycle(graph, color, states))
        return false;

    return true;
  }

  private boolean hasCycle(Set<Integer>[] graph, int u, State[] states) {
    if (states[u] == State.kVisiting)
      return true;
    if (states[u] == State.kVisited)
      return false;

    states[u] = State.kVisiting;
    for (int v : graph[u])
      if (hasCycle(graph, v, states))
        return true;
    states[u] = State.kVisited;

    return false;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from enum import Enum


class State(Enum):
  kInit = 0
  kVisiting = 1
  kVisited = 2


class Solution:
  def isPrintable(self, targetGrid: list[list[int]]) -> bool:
    kMaxColor = 60
    m = len(targetGrid)
    n = len(targetGrid[0])

    # graph[u] := {v1, v2} means v1 and v2 cover u
    graph = [set() for _ in range(kMaxColor + 1)]

    for color in range(1, kMaxColor + 1):
      # Get the rectangle of the current color.
      minI = m
      minJ = n
      maxI = -1
      maxJ = -1
      for i in range(m):
        for j in range(n):
          if targetGrid[i][j] == color:
            minI = min(minI, i)
            minJ = min(minJ, j)
            maxI = max(maxI, i)
            maxJ = max(maxJ, j)

      # Add any color covering the current as the children.
      for i in range(minI, maxI + 1):
        for j in range(minJ, maxJ + 1):
          if targetGrid[i][j] != color:
            graph[color].add(targetGrid[i][j])

    states = [State.kInit] * (kMaxColor + 1)

    def hasCycle(u: int) -> bool:
      if states[u] == State.kVisiting:
        return True
      if states[u] == State.kVisited:
        return False

      states[u] = State.kVisiting
      if any(hasCycle(v) for v in graph[u]):
        return True
      states[u] = State.kVisited

      return False

    return not (any(hasCycle(i) for i in range(1, kMaxColor + 1)))