|
6 | 6 |
|
7 | 7 | <!-- 这里写题目描述 -->
|
8 | 8 |
|
9 |
| -<p>给定一个非空01二维数组表示的网格,一个岛屿由四连通(上、下、左、右四个方向)的 <code>1</code> 组成,你可以认为网格的四周被海水包围。</p> |
| 9 | +<p>给定一个 <code>m x n</code> 二进制数组表示的网格 <code>grid</code> ,一个岛屿由 <strong>四连通</strong> (上、下、左、右四个方向)的 <code>1</code> 组成(代表陆地)。你可以认为网格的四周被海水包围。</p> |
10 | 10 |
|
11 |
| -<p>请你计算这个网格中共有多少个形状不同的岛屿。如果两个岛屿的形状相同,或者通过旋转(顺时针旋转 90°,180°,270°)、翻转(左右翻转、上下翻转)后形状相同,那么就认为这两个岛屿是相同的。</p> |
| 11 | +<p>如果两个岛屿的形状相同,或者通过旋转(顺时针旋转 90°,180°,270°)、翻转(左右翻转、上下翻转)后形状相同,那么就认为这两个岛屿是相同的。</p> |
12 | 12 |
|
13 |
| -<p> </p> |
14 |
| - |
15 |
| -<p><strong>样例 1:</strong></p> |
16 |
| - |
17 |
| -<pre>11000 |
18 |
| -10000 |
19 |
| -00001 |
20 |
| -00011 |
21 |
| -</pre> |
22 |
| - |
23 |
| -<p>给定上图,返回结果 <code>1</code>。<br> |
24 |
| -<br> |
25 |
| -注意 :</p> |
26 |
| - |
27 |
| -<pre>11 |
28 |
| -1 |
29 |
| -</pre> |
30 |
| - |
31 |
| -<p>和</p> |
32 |
| - |
33 |
| -<pre> 1 |
34 |
| -11</pre> |
35 |
| - |
36 |
| -<p>是相同的岛屿。因为我们通过 180° 旋转第一个岛屿,两个岛屿的形状相同。</p> |
| 13 | +<p>返回 <em>这个网格中形状 <strong>不同</strong> 的岛屿的数量 </em>。</p> |
37 | 14 |
|
38 | 15 | <p> </p>
|
39 | 16 |
|
40 |
| -<p><strong>样例 2:</strong></p> |
| 17 | +<p><strong>示例 1:</strong></p> |
41 | 18 |
|
42 |
| -<pre>11100 |
43 |
| -10001 |
44 |
| -01001 |
45 |
| -01110</pre> |
| 19 | +<p><img src="https://cdn.jsdelivr.net/gh/doocs/leetcode@main/solution/0700-0799/0711.Number%20of%20Distinct%20Islands%20II/images/distinctisland2-1-grid.jpg" style="height: 162px; width: 200px;" /></p> |
46 | 20 |
|
47 |
| -<p>给定上图,返回结果 <code>2</code>。<br> |
48 |
| -<br> |
49 |
| -下面是两个不同的岛屿:</p> |
| 21 | +<pre> |
| 22 | +<strong>输入:</strong> grid = [[1,1,0,0,0],[1,0,0,0,0],[0,0,0,0,1],[0,0,0,1,1]] |
| 23 | +<strong>输出:</strong> 1 |
| 24 | +<strong>解释:</strong> 这两个是相同的岛屿。因为我们通过 180° 旋转第一个岛屿,两个岛屿的形状相同。 |
| 25 | +</pre> |
50 | 26 |
|
51 |
| -<pre>111 |
52 |
| -1</pre> |
| 27 | +<p><strong>示例 2:</strong></p> |
53 | 28 |
|
54 |
| -<p>和</p> |
| 29 | +<p><img alt="" src="https://cdn.jsdelivr.net/gh/doocs/leetcode@main/solution/0700-0799/0711.Number%20of%20Distinct%20Islands%20II/images/distinctisland1-1-grid.jpg" style="height: 162px; width: 200px;" /></p> |
55 | 30 |
|
56 |
| -<pre>1 |
57 |
| -1 |
| 31 | +<pre> |
| 32 | +<strong>输入:</strong> grid = [[1,1,0,0,0],[1,1,0,0,0],[0,0,0,1,1],[0,0,0,1,1]] |
| 33 | +<strong>输出:</strong> 1 |
58 | 34 | </pre>
|
59 | 35 |
|
60 | 36 | <p> </p>
|
61 | 37 |
|
62 |
| -<p>注意 :</p> |
63 |
| - |
64 |
| -<pre>111 |
65 |
| -1</pre> |
| 38 | +<p><strong>提示:</strong></p> |
66 | 39 |
|
67 |
| -<p>和</p> |
| 40 | +<ul> |
| 41 | + <li><code>m == grid.length</code></li> |
| 42 | + <li><code>n == grid[i].length</code></li> |
| 43 | + <li><code>1 <= m, n <= 50</code></li> |
| 44 | + <li><code>grid[i][j]</code> 不是 <code>0</code> 就是 <code>1</code>.</li> |
| 45 | +</ul> |
68 | 46 |
|
69 |
| -<pre>1 |
70 |
| -111 |
71 |
| -</pre> |
72 |
| - |
73 |
| -<p>相同的岛屿。因为我们通过上下翻转第一个岛屿,两个岛屿的形状相同。</p> |
| 47 | +## 解法 |
74 | 48 |
|
75 |
| -<p> </p> |
| 49 | +<!-- 这里可写通用的实现逻辑 --> |
76 | 50 |
|
77 |
| -<p><strong>注释 :</strong> 二维数组每维的大小都不会超过50。</p> |
| 51 | +先利用 DFS 找出每个岛屿,随后对岛屿进行翻转、旋转等操作,得到以下 8 种不同的情况,并对这些情况进行标准化 `normalize` 处理,得到该岛屿的特征值,放到哈希表中。最后返回哈希表的元素数量即可。 |
78 | 52 |
|
79 |
| -## 解法 |
| 53 | +``` |
| 54 | +原坐标: (i, j) |
| 55 | +上下翻转: (i, -j) |
| 56 | +左右翻转: (-i, j) |
| 57 | +90°旋转: (j, -i) |
| 58 | +180°旋转: (-i, -j) |
| 59 | +270°旋转: (-j, -i) |
| 60 | +90°旋转+左右翻转: (-j, -i) |
| 61 | +90°旋转+上下翻转: (j, i) |
| 62 | +``` |
80 | 63 |
|
81 |
| -<!-- 这里可写通用的实现逻辑 --> |
| 64 | +标准化 `normalize` 的思路是:对于岛屿的每一种情况,先按照横、纵坐标升序排列坐标点,得到的第一个点 `(a, b)` 是最小的点,将其化为 `(0, 0)`,对于其他点 `(x, y)`,则化为 `(x - a, y - b)`。然后排序这 8 种情况,获取最小的一种,作为该岛屿的标准化值。 |
82 | 65 |
|
83 | 66 | <!-- tabs:start -->
|
84 | 67 |
|
|
87 | 70 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
88 | 71 |
|
89 | 72 | ```python
|
90 |
| - |
| 73 | +class Solution: |
| 74 | + def numDistinctIslands2(self, grid: List[List[int]]) -> int: |
| 75 | + def dfs(i, j, shape): |
| 76 | + shape.append([i, j]) |
| 77 | + grid[i][j] = 0 |
| 78 | + for a, b in [[1, 0], [-1, 0], [0, 1], [0, -1]]: |
| 79 | + x, y = i + a, j + b |
| 80 | + if 0 <= x < m and 0 <= y < n and grid[x][y] == 1: |
| 81 | + dfs(x, y, shape) |
| 82 | + |
| 83 | + def normalize(shape): |
| 84 | + shapes = [[] for _ in range(8)] |
| 85 | + for i, j in shape: |
| 86 | + shapes[0].append([i, j]) |
| 87 | + shapes[1].append([i, -j]) |
| 88 | + shapes[2].append([-i, j]) |
| 89 | + shapes[3].append([-i, -j]) |
| 90 | + shapes[4].append([j, i]) |
| 91 | + shapes[5].append([j, -i]) |
| 92 | + shapes[6].append([-j, i]) |
| 93 | + shapes[7].append([-j, -i]) |
| 94 | + for e in shapes: |
| 95 | + e.sort() |
| 96 | + for i in range(len(e) - 1, -1, -1): |
| 97 | + e[i][0] -= e[0][0] |
| 98 | + e[i][1] -= e[0][1] |
| 99 | + shapes.sort() |
| 100 | + return tuple(tuple(e) for e in shapes[0]) |
| 101 | + |
| 102 | + m, n = len(grid), len(grid[0]) |
| 103 | + s = set() |
| 104 | + for i in range(m): |
| 105 | + for j in range(n): |
| 106 | + if grid[i][j]: |
| 107 | + shape = [] |
| 108 | + dfs(i, j, shape) |
| 109 | + s.add(normalize(shape)) |
| 110 | + return len(s) |
91 | 111 | ```
|
92 | 112 |
|
93 | 113 | ### **Java**
|
94 | 114 |
|
95 | 115 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
96 | 116 |
|
97 | 117 | ```java
|
| 118 | +class Solution { |
| 119 | + private int m; |
| 120 | + private int n; |
| 121 | + private int[][] grid; |
| 122 | + |
| 123 | + public int numDistinctIslands2(int[][] grid) { |
| 124 | + m = grid.length; |
| 125 | + n = grid[0].length; |
| 126 | + this.grid = grid; |
| 127 | + Set<List<List<Integer>>> s = new HashSet<>(); |
| 128 | + for (int i = 0; i < m; ++i) { |
| 129 | + for (int j = 0; j < n; ++j) { |
| 130 | + if (grid[i][j] == 1) { |
| 131 | + List<Integer> shape = new ArrayList<>(); |
| 132 | + dfs(i, j, shape); |
| 133 | + s.add(normalize(shape)); |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + return s.size(); |
| 138 | + } |
| 139 | + |
| 140 | + private List<List<Integer>> normalize(List<Integer> shape) { |
| 141 | + List<int[]>[] shapes = new List[8]; |
| 142 | + for (int i = 0; i < 8; ++i) { |
| 143 | + shapes[i] = new ArrayList<>(); |
| 144 | + } |
| 145 | + for (int e : shape) { |
| 146 | + int i = e / n; |
| 147 | + int j = e % n; |
| 148 | + shapes[0].add(new int[]{i, j}); |
| 149 | + shapes[1].add(new int[]{i, -j}); |
| 150 | + shapes[2].add(new int[]{-i, j}); |
| 151 | + shapes[3].add(new int[]{-i, -j}); |
| 152 | + shapes[4].add(new int[]{j, i}); |
| 153 | + shapes[5].add(new int[]{j, -i}); |
| 154 | + shapes[6].add(new int[]{-j, i}); |
| 155 | + shapes[7].add(new int[]{-j, -i}); |
| 156 | + } |
| 157 | + for (List<int[]> e : shapes) { |
| 158 | + e.sort((a, b) -> { |
| 159 | + int i1 = a[0]; |
| 160 | + int j1 = a[1]; |
| 161 | + int i2 = b[0]; |
| 162 | + int j2 = b[1]; |
| 163 | + if (i1 == i2) { |
| 164 | + return j1 - j2; |
| 165 | + } |
| 166 | + return i1 - i2; |
| 167 | + }); |
| 168 | + int a = e.get(0)[0]; |
| 169 | + int b = e.get(0)[1]; |
| 170 | + for (int k = e.size() - 1; k >= 0; --k) { |
| 171 | + int i = e.get(k)[0]; |
| 172 | + int j = e.get(k)[1]; |
| 173 | + e.set(k, new int[]{i - a, j - b}); |
| 174 | + } |
| 175 | + } |
| 176 | + Arrays.sort(shapes, (a, b) -> { |
| 177 | + for (int k = 0; k < a.size(); ++k) { |
| 178 | + int i1 = a.get(k)[0]; |
| 179 | + int j1 = a.get(k)[1]; |
| 180 | + int i2 = b.get(k)[0]; |
| 181 | + int j2 = b.get(k)[1]; |
| 182 | + if (i1 != i2) { |
| 183 | + return i1 - i2; |
| 184 | + } |
| 185 | + if (j1 != j2) { |
| 186 | + return j1 - j2; |
| 187 | + } |
| 188 | + } |
| 189 | + return 0; |
| 190 | + }); |
| 191 | + List<List<Integer>> ans = new ArrayList<>(); |
| 192 | + for (int[] e : shapes[0]) { |
| 193 | + ans.add(Arrays.asList(e[0], e[1])); |
| 194 | + } |
| 195 | + return ans; |
| 196 | + } |
| 197 | + |
| 198 | + private void dfs(int i, int j, List<Integer> shape) { |
| 199 | + shape.add(i * n + j); |
| 200 | + grid[i][j] = 0; |
| 201 | + int[] dirs = {-1, 0, 1, 0, -1}; |
| 202 | + for (int k = 0; k < 4; ++k) { |
| 203 | + int x = i + dirs[k]; |
| 204 | + int y = j + dirs[k + 1]; |
| 205 | + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) { |
| 206 | + dfs(x, y, shape); |
| 207 | + } |
| 208 | + } |
| 209 | + } |
| 210 | +} |
| 211 | +``` |
98 | 212 |
|
| 213 | +### **C++** |
| 214 | + |
| 215 | +```cpp |
| 216 | +typedef pair<int,int> PII; |
| 217 | + |
| 218 | +class Solution { |
| 219 | +public: |
| 220 | + int numDistinctIslands2(vector<vector<int>>& grid) { |
| 221 | + set<vector<PII>> s; |
| 222 | + for (int i = 0; i < grid.size(); ++i) |
| 223 | + { |
| 224 | + for (int j = 0; j < grid[0].size(); ++j) |
| 225 | + { |
| 226 | + if (grid[i][j]) |
| 227 | + { |
| 228 | + vector<PII> shape; |
| 229 | + dfs(i, j, grid, shape); |
| 230 | + s.insert(normalize(shape)); |
| 231 | + } |
| 232 | + } |
| 233 | + } |
| 234 | + return s.size(); |
| 235 | + } |
| 236 | + |
| 237 | + vector<PII> normalize(vector<PII>& shape) { |
| 238 | + vector<vector<PII>> shapes(8); |
| 239 | + for (auto& e : shape) |
| 240 | + { |
| 241 | + int i = e.first, j = e.second; |
| 242 | + shapes[0].push_back({i, j}); |
| 243 | + shapes[1].push_back({i, -j}); |
| 244 | + shapes[2].push_back({-i, j}); |
| 245 | + shapes[3].push_back({-i, -j}); |
| 246 | + shapes[4].push_back({j, i}); |
| 247 | + shapes[5].push_back({j, -i}); |
| 248 | + shapes[6].push_back({-j, -i}); |
| 249 | + shapes[7].push_back({-j, i}); |
| 250 | + } |
| 251 | + for (auto& e : shapes) |
| 252 | + { |
| 253 | + sort(e.begin(), e.end()); |
| 254 | + for (int k = e.size() - 1; k >= 0; --k) |
| 255 | + { |
| 256 | + e[k].first -= e[0].first; |
| 257 | + e[k].second -= e[0].second; |
| 258 | + } |
| 259 | + } |
| 260 | + sort(shapes.begin(), shapes.end()); |
| 261 | + return shapes[0]; |
| 262 | + } |
| 263 | + |
| 264 | + void dfs(int i, int j, vector<vector<int>>& grid, vector<PII>& shape) { |
| 265 | + shape.push_back({i, j}); |
| 266 | + grid[i][j] = 0; |
| 267 | + vector<int> dirs = {-1, 0, 1, 0, -1}; |
| 268 | + for (int k = 0; k < 4; ++k) |
| 269 | + { |
| 270 | + int x = i + dirs[k], y = j + dirs[k + 1]; |
| 271 | + if (x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size() && grid[x][y] == 1) |
| 272 | + dfs(x, y, grid, shape); |
| 273 | + } |
| 274 | + } |
| 275 | +}; |
99 | 276 | ```
|
100 | 277 |
|
101 | 278 | ### **...**
|
|
0 commit comments