力扣的这一题把我搞死了,题目的描述和解题思路实际都挺简单的,但是呢,我对C++的语法生疏的太厉害,在小细节的设置太差劲了,所以这一题必须记录一下:
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这个思路其实很简单:每次选择一个没有登陆过的point(登陆点),然后使用广度遍历,标记所有和它通联的point。那么登陆点的数量就是岛屿的数量。这个代码我很快就写出来了,大概是这样的:
bool is_walk(grid, is_, i, j) ://判断是否走过
if is_[i][j] == true:
return false //走过
else:
return true // 没走过
int walk(grid, is_, i, j) //遍历
if grid(i, j)越界:
return 0;
if !is_walk(grid, i, j): //走过
return 1;
walk(i-1, j) //上
walk(i, j+1) //右
walk(i+1, j) //下
walk(i,j-1) //左
return 1;
虽然思路繁琐,但是还是对的,不过这里有一个问题,is_ 是二维数组,我在二维指针的使用上,耽误了很久。这里的【链接】作为二维指针的总结。
其实仔细分析一下,这里面是太复杂的,首先walk之后,grid[i][j]本身就能作为是否走过的指标,不需要多使用一个二维数组,这是以前留下的坏习惯。代码可以直接简化:
void walk(grid, i, j):
if (i,j 越界):
return;
if grid[i][j] == '2' //表示已经走过
return;
grid[i][j] = '2'
walk(i-1, j) //上
walk(i, j+1) //右
walk(i+1, j) //下
walk(i, j-1) //左
return;
这个简化的代码很简单。具体代码是这样的:
void walk(vector<vector<char>>& grid, int i, int j) {
if(i>=0 && j>=0 && i<grid.size() && j<grid[0].size());
else return;
if (grid[i][j]=='1')
grid[i][j] = '2';
else
return;
walk(grid, i-1, j);
walk(grid, i, j+1);
walk(grid, i+1, j);
walk(grid, i, j-1);
return;
}
int numIslands(vector<vector<char>>& grid) {
int count = 0;
for(int i=0; i<grid.size(); i++)
for(int j=0; j<grid[0].size(); j++)
if(grid[i][j]=='1')
{
count++;
walk(grid, i, j);
}
return count;
}
但是,之前有一个问题,简化后,最开始的是这样的:
int height = grid.size();
int width = grid[0].size(); //这里是有问题的
for(int i=0; i<height; i++)
for(int j=0; j<width; j++)
{
...
}
这样写咋看是没有问题, height 和 width的使用也是我的代码习惯,不过这里面有一个bug:当grid = []时, grid[0]是越界的!
这题花了我二十个头发,哈哈哈哈。