1020. 飞地的数量(BFS 和并查集)
作者:互联网
1020. 飞地的数量
给你一个大小为 m x n
的二进制矩阵 grid
,其中 0
表示一个海洋单元格、1
表示一个陆地单元格。
一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid
的边界。
返回网格中 无法 在任意次数的移动中离开网格边界的陆地单元格的数量。
示例 1:
输入:grid = [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]] 输出:3 解释:有三个 1 被 0 包围。一个 1 没有被包围,因为它在边界上。
示例 2:
输入: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
方法一:(BFS)
1 class Solution { 2 public: 3 bool isInArea(int x, int y) { 4 return (x >= 0 && x < row && y >= 0 && y < col); 5 } 6 void addBoundryLandToQueue(const vector<vector<int>> &grid, queue<std::pair<int, int>> &q, vector<vector<bool>> &visited) { 7 // 左右边界的陆地入队 8 for (int i = 0; i < row; i++) { 9 // 左边界陆地入队 10 if (grid[i][0] == 1) { 11 q.push(make_pair(i, 0)); 12 visited[i][0] = true; 13 } 14 // 右边界陆地入队 15 if (grid[i][col - 1] == 1) { 16 q.push(make_pair(i, col - 1)); 17 visited[i][col - 1] = true; 18 } 19 } 20 // 上下边界的陆地入队 21 for (int j = 1; j < col - 1; j++) { 22 // 上边界陆地入队 23 if (grid[0][j] == 1) { 24 q.push(make_pair(0, j)); 25 visited[0][j] = true; 26 } 27 // 下边界陆地入队 28 if (grid[row - 1][j] == 1) { 29 q.push(make_pair(row - 1, j)); 30 visited[row - 1][j] = true; 31 } 32 } 33 } 34 void bfsUpdateNeighborLandVisited(const vector<vector<int>> &grid, queue<std::pair<int,int>> &q, vector<vector<bool>> &visited) { 35 while (!q.empty()) { 36 int curX = q.front().first; 37 int curY = q.front().second; 38 q.pop(); 39 for (auto &direction : g_direction) { 40 int nextX = curX + direction[0]; 41 int nextY = curY + direction[1]; 42 /* 43 * 1、不在矩阵范围内的跳过 44 * 2、海洋方格跳过 45 * 3、已访问的跳过 46 */ 47 if (!isInArea(nextX, nextY) || grid[nextX][nextY] == 0 || visited[nextX][nextY]) { 48 continue; 49 } 50 q.push(make_pair(nextX, nextY)); // 相邻陆地入队 51 visited[nextX][nextY] = true; // 设置相邻陆地已访问 52 } 53 } 54 } 55 int getUnreachedLand(const vector<vector<int>> &grid, const vector<vector<bool>> &visited) { 56 int cnt = 0; 57 for (int i = 0; i < row; i++) { 58 for (int j = 0; j < col; j++) { 59 if (grid[i][j] == 1 && !visited[i][j]) { 60 cnt++; 61 } 62 } 63 } 64 return cnt; 65 } 66 int numEnclaves(vector<vector<int>>& grid) { 67 row = grid.size(); 68 col = grid[0].size(); 69 vector<vector<bool>> visited(row, vector<bool>(col, false)); 70 queue<std::pair<int, int>> q; 71 // 1、将边界陆地入队并设置已访问 72 addBoundryLandToQueue(grid, q, visited); 73 // 2、BFS矩阵刷新与边界相连的陆地并设置已访问 74 bfsUpdateNeighborLandVisited(grid, q, visited); 75 // 3、遍历方格统计未访问陆地数,即为无论怎么移动都不能离开边界的陆地单元格数量 76 return getUnreachedLand(grid, visited); 77 } 78 private: 79 int row; 80 int col; 81 // 顺时针上、右、下、左四个方向 82 vector<vector<int>> g_direction = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; 83 };
方法二:(并查集)
1 class UnionFindSet { 2 public: 3 void init(int n) { 4 parent.resize(n); 5 for (int i = 0 ; i < n; i++) { 6 parent[i] = i; 7 } 8 } 9 int findRoot(int x) { 10 if (x != parent[x]) { 11 parent[x] = findRoot(parent[x]); 12 } 13 return parent[x]; 14 } 15 bool isConnected(int x, int y) { 16 return (findRoot(x) == findRoot(y)); 17 } 18 void unify(int x, int y) { 19 if (isConnected(x, y)) { 20 return; 21 } 22 int xRoot = findRoot(x); 23 int yRoot = findRoot(y); 24 parent[xRoot] = yRoot; 25 return; 26 } 27 private: 28 vector<int> parent; 29 }; 30 31 class Solution : public UnionFindSet { 32 public: 33 bool isInArea(int x, int y) { 34 return (x >= 0 && x < row && y >= 0 && y < col); 35 } 36 int numEnclaves(vector<vector<int>>& grid) { 37 row = grid.size(); 38 col = grid[0].size(); 39 int n = row * col + 10; // 二维数组转换为一维,多分点内存防止越界访问 40 // 1、初始化并查集 41 init(n); 42 // 2、虚拟一个节点作为树的根节点row * col,将边界陆地与之相连 43 // 左、右边界陆地与虚拟根节点相连 44 for (int i = 0; i < row; i++) { 45 if (grid[i][0] == 1) { 46 // 转换为一维坐标:i * col + 0与虚拟根节点row * col相连 47 unify(i * col, row * col); 48 } 49 if (grid[i][col - 1] == 1) { 50 // 转换为一维坐标:i * col + col - 1与虚拟根节点row * col相连 51 unify(i * col + col - 1, row * col); 52 } 53 } 54 // 上、下边界陆地与虚拟节点相连 55 for (int j = 0; j < col; j++) { 56 if (grid[0][j] == 1) { 57 // 转换为一维坐标:0 * col + j与虚拟根节点row * col相连 58 unify(j, row * col); 59 } 60 if (grid[row - 1][j] == 1) { 61 // 转换为一维坐标:(row - 1) * col + j与虚拟根节点row * col相连 62 unify((row - 1) * col + j, row * col); 63 } 64 } 65 // 3、遍历矩阵方格,将陆地相连 66 for (int i = 0; i < row; i++) { 67 for (int j = 0; j < col; j++) { 68 if (grid[i][j] == 0) { 69 continue; 70 } 71 for (auto &direction : g_direction) { 72 int nextX = i + direction[0]; 73 int nextY = j + direction[1]; 74 if (!isInArea(nextX, nextY) || grid[nextX][nextY] == 0) { 75 continue; 76 } 77 unify(nextX * col + nextY, i * col + j); 78 } 79 } 80 } 81 // 4、遍历矩阵非边界方格,统计未与虚拟根节点相连的陆地,即为即为无论怎么移动都不能离开边界的陆地单元格数量 82 int cnt = 0; 83 for (int i = 1; i < row - 1; i++) { 84 for (int j = 1; j < col - 1; j++) { 85 if (grid[i][j] == 1 && !isConnected(i * col + j, row * col)) { 86 cnt++; 87 } 88 } 89 } 90 return cnt; 91 } 92 private: 93 int row; 94 int col; 95 // 顺时针上、右、下、左四个方向 96 vector<vector<int>> g_direction = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; 97 };
标签:陆地,1020,int,查集,BFS,grid,visited,col,row 来源: https://www.cnblogs.com/MGFangel/p/16298052.html