|
3 | 3 | // Space: O(e)
|
4 | 4 |
|
5 | 5 | class Solution {
|
| 6 | +public: |
| 7 | + bool isPrintable(vector<vector<int>>& targetGrid) { |
| 8 | + unordered_map<int, vector<int>> boxes; |
| 9 | + for (int r = 0; r < size(targetGrid); ++r) { |
| 10 | + for (int c = 0; c < size(targetGrid[r]); ++c) { |
| 11 | + if (!boxes.count(targetGrid[r][c])) { |
| 12 | + boxes[targetGrid[r][c]] = {r, c, r, c}; |
| 13 | + } else { |
| 14 | + boxes[targetGrid[r][c]][0] = min(boxes[targetGrid[r][c]][0], r); |
| 15 | + boxes[targetGrid[r][c]][1] = min(boxes[targetGrid[r][c]][1], c); |
| 16 | + boxes[targetGrid[r][c]][2] = max(boxes[targetGrid[r][c]][2], r); |
| 17 | + boxes[targetGrid[r][c]][3] = max(boxes[targetGrid[r][c]][3], c); |
| 18 | + } |
| 19 | + } |
| 20 | + } |
| 21 | + unordered_map<int, unordered_set<int>> adj; |
| 22 | + for (const auto& [color, box] : boxes) { |
| 23 | + for (int r = box[0]; r <= box[2]; ++r) { |
| 24 | + for (int c = box[1]; c <= box[3]; ++c) { |
| 25 | + if (targetGrid[r][c] != color) { |
| 26 | + adj[color].emplace(targetGrid[r][c]); |
| 27 | + } |
| 28 | + } |
| 29 | + } |
| 30 | + } |
| 31 | + unordered_map<int, int> lookup; |
| 32 | + for (const auto& [color, _] : boxes) { |
| 33 | + if (lookup.count(color)) { |
| 34 | + continue; |
| 35 | + } |
| 36 | + if (hasCycle(adj, color, &lookup)) { |
| 37 | + return false; |
| 38 | + } |
| 39 | + } |
| 40 | + return true; |
| 41 | + } |
| 42 | + |
| 43 | +private: |
| 44 | + enum State {VISITING, VISITED}; |
| 45 | + |
| 46 | + bool hasCycle(const unordered_map<int, unordered_set<int>>& adj, |
| 47 | + int color, |
| 48 | + unordered_map<int, int> *lookup) { |
| 49 | + vector<pair<int, int>> stk = {{1, color}}; |
| 50 | + while (!empty(stk)) { |
| 51 | + const auto [step, color] = stk.back(); stk.pop_back(); |
| 52 | + if (step == 1) { |
| 53 | + (*lookup)[color] = VISITING; |
| 54 | + stk.emplace_back(2, color); |
| 55 | + if (!adj.count(color)) { |
| 56 | + continue; |
| 57 | + } |
| 58 | + for (const auto& new_color : adj.at(color)) { |
| 59 | + if (lookup->count(new_color)) { |
| 60 | + if ((*lookup)[new_color] == VISITED) { |
| 61 | + continue; |
| 62 | + } |
| 63 | + return true; // VISITING |
| 64 | + } |
| 65 | + stk.emplace_back(1, new_color); |
| 66 | + } |
| 67 | + } else { |
| 68 | + (*lookup)[color] = VISITED; |
| 69 | + } |
| 70 | + } |
| 71 | + return false; |
| 72 | + } |
| 73 | +}; |
| 74 | + |
| 75 | +// Time: O(c * m * n + e), c is the number of colors |
| 76 | +// , e is the number of edges in adj, at most O(c^2) |
| 77 | +// Space: O(e) |
| 78 | +class Solution2 { |
6 | 79 | public:
|
7 | 80 | bool isPrintable(vector<vector<int>>& targetGrid) {
|
8 | 81 | static const int MAX_COLOR = 60;
|
@@ -49,28 +122,16 @@ class Solution {
|
49 | 122 | bool hasCycle(const unordered_map<int, unordered_set<int>>& adj,
|
50 | 123 | int color,
|
51 | 124 | unordered_map<int, int> *lookup) {
|
52 |
| - vector<pair<int, int>> stk = {{1, color}}; |
53 |
| - while (!empty(stk)) { |
54 |
| - const auto [step, color] = stk.back(); stk.pop_back(); |
55 |
| - if (step == 1) { |
56 |
| - (*lookup)[color] = VISITING; |
57 |
| - stk.emplace_back(2, color); |
58 |
| - if (!adj.count(color)) { |
59 |
| - continue; |
| 125 | + (*lookup)[color] = VISITING; |
| 126 | + if (adj.count(color)) { |
| 127 | + for (const auto& new_color : adj.at(color)) { |
| 128 | + if ((!lookup->count(new_color) && hasCycle(adj, new_color, lookup)) || |
| 129 | + (*lookup)[new_color] == VISITING) { |
| 130 | + return true; |
60 | 131 | }
|
61 |
| - for (const auto& new_color : adj.at(color)) { |
62 |
| - if (lookup->count(new_color)) { |
63 |
| - if ((*lookup)[new_color] == VISITED) { |
64 |
| - continue; |
65 |
| - } |
66 |
| - return true; // VISITING |
67 |
| - } |
68 |
| - stk.emplace_back(1, new_color); |
69 |
| - } |
70 |
| - } else { |
71 |
| - (*lookup)[color] = VISITED; |
72 | 132 | }
|
73 | 133 | }
|
| 134 | + (*lookup)[color] = VISITED; |
74 | 135 | return false;
|
75 | 136 | }
|
76 | 137 | };
|
0 commit comments