题目描述
知识点
深度优先搜索 或者 并查集
结果
我挺满意哒
实现
码前思考
我是在并查集的章节里面看到这个题目的,但是由于题目的性质,我最后选择了使用DFS来解题,那是什么性质导致我选择DFS来解题呢?
- 首先剥去小岛的外壳,我们可以发现这其实就是一个求连通分量的题目;
- 对于这种在二维矩阵中上、下、左、右移动的题目,我们通常使用的是深度优先搜索,比如说之前做过的一道动态规划的题目——LeetCode 329. Longest Increasing Path in a Matrix,他用的就是记忆化DFS,通常DFS总能通过记忆化来降低时间复杂度的!
- 这里的“连通分量”类似于咱们的并查集中的“集”;
- 需要另外注意的是:
- 对于这种
2d
array的题目,最好是保持2d
不变,不要映射成1d
; - 四种方向可以通过数组来表示,从而增强代码可读性:
int dr[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
代码实现
//1. 题目的意思实际上就是找图中的连通分量
//2. 对于这种上下左右移动的题,我们要考虑一些深度优先搜素!
//3. 类似于并查集中的“集”
class Solution {
private:
//记录在哪一个连通分量里面的
vector<vector<int>> father;
//记录连通分量的个数 number of component
int nc;
//DFS的方向,只有向下和向右两个方向
int dr[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
int m;
int n;
public:
int numIslands(vector<vector<char>>& grid) {
//获取grid大小
m = grid.size();
//特判
if(m==0){
return 0;
}
n = grid[0].size();
//初始化father数组
father.assign(m,vector<int>(n,-1));
nc=0;
//遍历每一个元素
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(father[i][j]!=-1){
continue;
}else if(grid[i][j] == '1'){
DFS(i,j,grid);
nc++;
}
}
}
return nc;
}
//函数的意思是设置当前坐标及其邻居的father
//这里DFS的返现有一些小技巧
void DFS(int i,int j,vector<vector<char>>& grid){
//如果当前为‘0’
if(grid[i][j] == '0'){
return;
}
//记忆化搜索,直接返回
if(father[i][j] != -1){
return;
}
//设置当前坐标及其邻居的father
father[i][j] = nc;
for(int k=0;k<4;k++){
int x = i + dr[k][0];
int y = j + dr[k][1];
if(x < m && y < n && x>=0 && y>=0){
DFS(x,y,grid);
}
}
}
};
码后反思
关于代码的问题:
- 其实
father
只要设置成bool
型的就好了,没必要设置成int
; - 先前以为只要向下和向右走就可以了,以为可以耍小聪明,结果忽视了有边界的问题,导致解答错误。。。看来要么思考清楚,要么稳中求胜!不要刷小聪明!
其他:
- 关于 并查集 实现可以参考这里,大家的题解写的好认真啊(๑•̀ㅂ•́)و✧
二刷代码
这次使用的DFS更加地简单和明了:
//使用DFS进行求解,其实就是一个求连通分支的问题
class Solution {
public:
int dir[4][4] = {{-1,0},{1,0},{0,-1},{0,1}};
int cnt = 0;
int m,n;
vector<vector<bool>> vis;
int numIslands(vector<vector<char>>& grid) {
m = grid.size();
if(m==0){
return 0;
}
n = grid[0].size();
vis.assign(m,vector<bool>(n,false));
//开始奇幻的dfs之旅
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(judge(i,j,grid)){
dfs(i,j,grid);
cnt++;
}
}
}
return cnt;
}
void dfs(int x,int y,vector<vector<char>>& grid){
vis[x][y] = true;
for(int i=0;i<4;i++){
int newX = x+dir[i][0];
int newY = y+dir[i][1];
if(judge(newX,newY,grid)){
dfs(newX,newY,grid);
}
}
}
bool judge(int x,int y,vector<vector<char>>& grid){
if(x<0||x>=m||y<0||y>=n){
return false;
}
if(vis[x][y]==true){
return false;
}
if(grid[x][y]=='0'){
return false;
}
return true;
}
};