200. 岛屿数量
难度:中
题目概述:找到属于同一个区域的点,典型的并查集问题。。
题解1:DFS
这道题不能采用修改原数组的值做访问标记,所以需要增加一个遍历标记数组。
有些题目,原数组的值会在遍历过程中被修改,所以通常可以直接用原数组的值做标记,进而节省内存。
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
vector<vector<bool>> visited(m, vector<bool>(n));
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[0].size(); ++j) {
if (grid[i][j] == '0' || visited[i][j]) continue;
dfs(grid, visited, i, j);
++res;
}
}
return res;
}
void dfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] == '0' || visited[x][y]) return;
visited[x][y] = true;
dfs(grid, visited, x - 1, y);
dfs(grid, visited, x + 1, y);
dfs(grid, visited, x, y - 1);
dfs(grid, visited, x, y + 1);
}
};
就dfs而言依然是一道模板题。
题解2:BFS
对于坐标的处理,可以不采用pair<int,int>的方式,因为pair标记坐标的处理开销要大于int。
通常可以将二维数组转化为一维数组进行处理,用行*列+列的方式标记。
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
int m = grid.size(), n = grid[0].size(), res = 0;
vector<vector<int>> visited(m, vector<int>(n));
vector<int> dirx{-1, 0, 1, 0}, diry{0, 1, 0, -1};
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == '0' || visited[i][j]) continue;
++res;
queue<int> q{{i * n + j}};
while (!q.empty()) {
int t = q.front(); q.pop();
for (int k = 0; k < 4; ++k) {
int x = t / n + dirx[k], y = t % n + diry[k];
if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == '0' || visited[x][y] == 1) continue;
visited[x][y] = 1;
q.push(x * n + y);
}
}
}
}
return res;
}
};
题解3:并查集
并查集三步法
1.建立根,初始化,每个节点为独立孤岛;建立find和uion函数。上述都是模板
2.根据表的结构关系,建立集合关系。(可能在完成这一步后,题目已经求解)
3.根据题目的具体要求,处理集合关系。
class Solution {
public:
vector<int> root_group;
int count=0;
int numIslands(vector<vector<char>>& grid) {
if (grid.size() == 0 || grid[0].size() == 0) return 0;
int length = grid.size() * grid[0].size();
int width = grid[0].size();
root_group = vector<int>(length, 0);
for(int i = 0; i < length; i++) {
int x = i / width, y = i % width;
if (grid[x][y] == '1') count++;
root_group[i] = i;
}
for(int j = 0; j < length; j++){
int x = j / width, y = j % width;
int down = x + 1, right = y + 1;
if (down < grid.size() && grid[x][y] == '1' && grid[down][y] == '1')
unin(j, j+width);
if ( right < grid[0].size() && grid[x][y] == '1' && grid[x][right] == '1')
unin(j, j+1);
}
return count;
}
void unin(int x,int y){
int rootx = find(x);
int rooty = find(y);
if (rootx == rooty)return;
root_group[rootx] = rooty;
count--;
}
int find(int p){
while (p != root_group[p]) {
root_group[p] = root_group[root_group[p]];
p = root_group[p];
}
return p;
}
};