其他分享
首页 > 其他分享> > 1020. 飞地的数量(BFS 和并查集)

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 都在边界上或可以到达边界。

 

提示:

方法一:(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