例题1:二维数组的岛屿问题
例题1.1:岛屿数量
分析:标准的dfs框架, 每遇到一个‘1’,都用dfs去淹没这个岛屿。
用dfs淹没岛屿,就不需要维护visited了,因为只要进入岛屿的其他块,因为被淹没了,直接判断grid[i][j] 为0,效果和visited是一样的。
代码:
class Solution {
public:
int m, n;
void dfs(vector<vector<char>>& grid,int i, int j){
if(i < 0 || j < 0|| i>= m || j>= n){
return;
}
if(grid[i][j] == '0'){
return;
}
grid[i][j] = '0';
dfs(grid, i+1, j);
dfs(grid, i, j+1);
dfs(grid, i-1, j);
dfs(grid, i, j-1);
}
int numIslands(vector<vector<char>>& grid) {
m = grid.size();
n = grid[0].size();
int ret = 0;
for(int i = 0; i< m; i++){
for(int j = 0; j< n; j++){
if(grid[i][j] == '1'){
ret++;
dfs(grid, i, j);
}
}
}
return ret;
}
};
例题1.2:统计封闭岛屿的数目
分析:和例题1基本相同,只需要加一个判断量,看看每一次淹没岛屿有没有触及到边界即可。
代码:
class Solution {
public:
int nums = 0;
int m, n;
bool ReachBorder = false;
void dfs(vector<vector<int>>& grid, int i, int j){
if(i < 0 || j<0 || i>=m || j >= n){
ReachBorder = true;
return;
}
if(grid[i][j] == 1){
return;
}
grid[i][j] = 1;
dfs(grid, i+1, j);
dfs(grid, i, j+1);
dfs(grid, i-1, j);
dfs(grid, i, j-1);
}
int closedIsland(vector<vector<int>>& grid) {
m = grid.size(); n = grid[0].size();
for(int i = 0; i< m; i++){
for(int j = 0; j< n; j++){
if(grid[i][j] == 0){
ReachBorder = false;
nums++;
dfs(grid, i, j);
if(ReachBorder){
nums--;
}
}
}
}
return nums;
}
};
例题1.3:飞地的数量
分析:和例题2差不多,区别在于每次淹没岛屿需要计数岛屿的大小,淹没完成后,如果没有触及边界才加上去。
代码:
class Solution {
public:
int nums, m, n;
int cnt;
bool reachBorder;
void dfs(vector<vector<int>>& grid, int i , int j){
if(i < 0 || j<0 || i>= m|| j>=n){
reachBorder = true;
return;
}
if(grid[i][j] == 0){
return;
}
grid[i][j] = 0;
cnt++;
dfs(grid, i+1, j);dfs(grid, i, j+1);dfs(grid, i-1, j);dfs(grid, i, j-1);
}
int numEnclaves(vector<vector<int>>& grid) {
m = grid.size(); n = grid[0].size();
for(int i = 0; i< m; i++){
for(int j = 0; j <n ; j++){
if(grid[i][j] == 1){
cnt = 0;reachBorder = false;
dfs(grid, i, j);
if(!reachBorder){
nums += cnt;
}
}
}
}
return nums;
}
};
例题1.4:岛屿的最大面积
分析:和例题
代码:
class Solution {
public:
int best, cnt;
int m, n;
void dfs(vector<vector<int>>& grid, int i, int j){
if(i<0||j<0||i>=m||j>=n){
return;
}
if(grid[i][j] == 0){
return;
}
grid[i][j] = 0;
cnt++;
dfs(grid, i+1, j);
dfs(grid, i-1, j);
dfs(grid, i, j+1);
dfs(grid, i, j-1);
}
int maxAreaOfIsland(vector<vector<int>>& grid) {
m = grid.size(); n = grid[0].size();
for(int i = 0; i< m; i++){
for(int j = 0; j<n; j++){
if(grid[i][j] == 1){
cnt = 0;
dfs(grid, i, j);
if(cnt > best){
best = cnt;
}
}
}
}
return best;
}
};
例题2:统计子岛屿
分析:
遍历grid2里面的每一个岛屿,只要对应的grid1格子都是陆地,它就一定是子岛屿。
代码:
class Solution {
public:
int m, n;
int isSub;
int ans = 0;
void dfs(vector<vector<int>>& grid1, vector<vector<int>>& grid2, int i, int j){
if (i<0 || j<0 || i>=m || j>= n){
return;
}
if(grid2[i][j] == 0){
return;
}
if(grid1[i][j] == 0){
isSub = 0;
}
grid2[i][j] = 0;
dfs(grid1, grid2, i+1, j);
dfs(grid1, grid2, i-1, j);
dfs(grid1, grid2, i, j+1);
dfs(grid1, grid2, i, j-1);
}
int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
m = grid1.size(); n = grid1[0].size();
for(int i = 0; i< m; i++){
for(int j = 0; j< n; j++){
if(grid2[i][j] == 1){
isSub = 1;
dfs(grid1, grid2, i, j);
if(isSub == 1){
ans++;
}
}
}
}
return ans;
}
};
.
例题3:岛屿的周长
分析:
修改grid的值来代替visit数组
代码:
class Solution {
public:
int m, n;
int ans = 0;
void dfs(vector<vector<int>>& grid, int i, int j){
if(i<0 || j<0 || i>= m|| j>= n || grid[i][j] == 0){
ans++;
return;
}
if(grid[i][j] == 2){
return;
}
grid[i][j] = 2;
dfs(grid, i+1, j);
dfs(grid, i-1, j);
dfs(grid, i, j+1);
dfs(grid, i, j-1);
}
int islandPerimeter(vector<vector<int>>& grid) {
m = grid.size(); n = grid[0].size();
for(int i = 0; i< m; i++){
for(int j = 0; j< n; j++){
if(grid[i][j] == 1){
dfs(grid, i, j);
break;
}
}
}
return ans;
}
};
例题4:被围绕的区域
分析:
代码:
class Solution {
public:
bool isSurrounded = true;
int m, n;
void dfs(vector<vector<char>>& board, int i, int j, int mode){
if(i<0 || j<0 || i>=m || j>= n){
isSurrounded = false;
return;
}
switch(mode){
case 0: if(board[i][j] == 'X' || board[i][j] == 'O'){
return;
}
board[i][j] = 'O';
break;
case 1: if(board[i][j] == 'X' || board[i][j] == 'V'){
return;
}
board[i][j] = 'V';
break;
case 2: if(board[i][j] == 'X'){
return;
}
board[i][j] = 'X';
break;
}
dfs(board, i+1, j, mode);
dfs(board, i-1, j, mode);
dfs(board, i, j+1, mode);
dfs(board, i, j-1, mode);
}
void solve(vector<vector<char>>& board) {
m = board.size(); n = board[0].size();
for(int i = 0; i< m; i++){
for(int j = 0 ; j< n; j++){
if(board[i][j] == 'O'){
isSurrounded = true;
dfs(board, i, j, 1);
if(isSurrounded){
dfs(board, i, j, 2);
}
else{
dfs(board, i, j, 0);
}
}
}
}
}
};
总结
i)淹没岛屿的作用是,不需要维护visited数组
ii)框架:
在主函数里,遍历每个块,每当遇到一个大陆,就用dfs去淹没它;dfs里,如果越界或者已经访问过这个块,直接返回,否则,递归访问它的相邻块。
维护一个全局变量,dfs的函数里面对它做出更新,然后在主函数返回。