diff --git "a/Index/\345\233\276\350\256\272 DFS.md" "b/Index/\345\233\276\350\256\272 DFS.md" index 8a00b3cb..d76e107e 100644 --- "a/Index/\345\233\276\350\256\272 DFS.md" +++ "b/Index/\345\233\276\350\256\272 DFS.md" @@ -4,6 +4,7 @@ | [778. 水位上升的泳池中游泳](https://leetcode-cn.com/problems/swim-in-rising-water/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/swim-in-rising-water/solution/gong-shui-san-xie-yi-ti-shuang-jie-krusk-7c6o/) | 困难 | 🤩🤩🤩 | | [797. 所有可能的路径](https://leetcode-cn.com/problems/all-paths-from-source-to-target/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/all-paths-from-source-to-target/solution/gong-shui-san-xie-yun-yong-dfs-bao-sou-s-xlz9/) | 中等 | 🤩🤩🤩🤩 | | [863. 二叉树中所有距离为 K 的结点](https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/solution/gong-shui-san-xie-yi-ti-shuang-jie-jian-x6hak/) | 中等 | 🤩🤩🤩🤩 | +| [1020. 飞地的数量](https://leetcode-cn.com/problems/number-of-enclaves/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-enclaves/solution/gong-shui-san-xie-bing-cha-ji-dfs-yun-yo-oyh1/) | 中等 | 🤩🤩🤩 | | [1034. 边界着色](https://leetcode-cn.com/problems/coloring-a-border/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/coloring-a-border/solution/gong-shui-san-xie-tu-lun-sou-suo-zhuan-t-snvw/) | 中等 | 🤩🤩🤩🤩 | | [1723. 完成所有工作的最短时间](https://leetcode-cn.com/problems/find-minimum-time-to-finish-all-jobs/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/find-minimum-time-to-finish-all-jobs/solution/gong-shui-san-xie-yi-ti-shuang-jie-jian-4epdd/) | 困难 | 🤩🤩🤩 | | [1766. 互质树](https://leetcode-cn.com/problems/tree-of-coprimes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/tree-of-coprimes/solution/bu-tai-yi-yang-de-dfs-ji-lu-suo-you-zui-d3xeu/) | 困难 | 🤩🤩🤩🤩 | diff --git "a/Index/\345\271\266\346\237\245\351\233\206.md" "b/Index/\345\271\266\346\237\245\351\233\206.md" index fcfc1fcf..b15fdeb4 100644 --- "a/Index/\345\271\266\346\237\245\351\233\206.md" +++ "b/Index/\345\271\266\346\237\245\351\233\206.md" @@ -2,5 +2,6 @@ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- | | [765. 情侣牵手](https://leetcode-cn.com/problems/couples-holding-hands/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/couples-holding-hands/solution/liang-chong-100-de-jie-fa-bing-cha-ji-ta-26a6/) | 困难 | 🤩🤩🤩 | | [778. 水位上升的泳池中游泳](https://leetcode-cn.com/problems/swim-in-rising-water/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/swim-in-rising-water/solution/gong-shui-san-xie-yi-ti-shuang-jie-krusk-7c6o/) | 困难 | 🤩🤩🤩 | +| [1020. 飞地的数量](https://leetcode-cn.com/problems/number-of-enclaves/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-enclaves/solution/gong-shui-san-xie-bing-cha-ji-dfs-yun-yo-oyh1/) | 中等 | 🤩🤩🤩 | | [1631. 最小体力消耗路径](https://leetcode-cn.com/problems/path-with-minimum-effort/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/path-with-minimum-effort/solution/fan-zheng-fa-zheng-ming-si-lu-de-he-fa-x-ohby/) | 中等 | 🤩🤩🤩 | diff --git "a/LeetCode/1011-1020/1020. \351\243\236\345\234\260\347\232\204\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1011-1020/1020. \351\243\236\345\234\260\347\232\204\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..0d90a105 --- /dev/null +++ "b/LeetCode/1011-1020/1020. \351\243\236\345\234\260\347\232\204\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,126 @@ +### 题目描述 + +这是 LeetCode 上的 **[1020. 飞地的数量](https://assets.leetcode.com/uploads/2021/02/18/enclaves1.jpg)** ,难度为 **中等**。 + +Tag : 「DFS」、「并查集」 + + + +给你一个大小为 $m x n$ 的二进制矩阵 $grid$ ,其中 $0$ 表示一个海洋单元格、$1$ 表示一个陆地单元格。 + +一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 $grid$ 的边界。 + +返回网格中 无法 在任意次数的移动中离开网格边界的陆地单元格的数量。 + +示例 1: +![](https://assets.leetcode.com/uploads/2021/02/18/enclaves1.jpg) +``` +输入:grid = [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]] + +输出:3 + +解释:有三个 1 被 0 包围。一个 1 没有被包围,因为它在边界上。 +``` +示例 2: +![](https://assets.leetcode.com/uploads/2021/02/18/enclaves2.jpg) +``` +输入:grid = [[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]] + +输出:0 + +解释:所有 1 都在边界上或可以到达边界。 +``` + +提示: +* $m == grid.length$ +* $n == grid[i].length$ +* $1 <= m, n <= 500$ +* $grid[i][j]$ 的值为 $0$ 或 $1$ + +--- + +### 并查集 + DFS + +根据题目定义,我们知道需要统计所有不和「边缘陆地」相连通的「普通陆地」数量。 + +我们可以用「并查集」来维护连通块,使用 `DFS` 对所有「边缘陆地连通块」进行标记(设定编号为 $0$ 的超级源点,对于所有的「边缘陆地连通块」,将其与超级源点联通)。 + +具体的,我们按照如下流程进行处理: + +* 初始化并查集:起始让每个单元格独立作为一个连通块; +* 使用 `DFS` 标记所有「边缘陆地连通块」:从位于边缘的「边缘陆地」进行出发,将其所在连通块与超级源点 $0$ 进行联通标记(同时为了确保复杂度,我们在进行 `DFS` 前需要先检查当前陆地与超级源点的联通关系,如果已联通,说明当前陆地棣属于之前的某个连通块,已被整体标记过,进行跳过即可); +* 统计答案:遍历整个棋盘,统计所有不与超级源点 $0$ 联通的陆地数量。 + +> 一些细节:由于我们人为规定了超级源点编号为 $0$,同时棋盘下标从 $0$ 开始,因此对某个点 $(x, y)$ 的编号,我们需要增加一个偏移量,例如 $idx = x * n + y + 1$。 + +代码: +```Java +class Solution { + int N = 550; + int[] p = new int[N * N]; + int m, n; + int[][] g; + int find(int x) { + if (p[x] != x) p[x] = find(p[x]); + return p[x]; + } + boolean query(int a, int b) { + return find(a) == find(b); + } + void union(int a, int b) { + p[find(a)] = find(b); + } + public int numEnclaves(int[][] grid) { + g = grid; + m = g.length; n = g[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + p[getIdx(i, j)] = getIdx(i, j); + } + } + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 || j == 0 || i == m - 1 || j == n - 1) { + if (g[i][j] != 1 || query(getIdx(i, j), 0)) continue; + dfs(i, j); + } + } + } + int ans = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (g[i][j] == 1 && !query(getIdx(i, j), 0)) ans++; + } + } + return ans; + } + int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}}; + void dfs(int x, int y) { + union(getIdx(x, y), 0); + for (int[] d : dirs) { + int nx = x + d[0], ny = y + d[1]; + if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue; + if (g[nx][ny] != 1 || query(getIdx(nx, ny), 0)) continue; + dfs(nx, ny); + } + } + int getIdx(int x, int y) { + return x * n + y + 1; + } +} +``` +* 时间复杂度:初始化并查集复杂度为 $O(m * n)$;使用 `DFS` 对边缘陆地连通块进行标记复杂度为 $O(m * n)$;统计答案复杂度为 $O(m * n)$。整体复杂度为 $O(m * n)$ +* 空间复杂度:$O(m * n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1011` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 +