岛屿数量问题
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1
示例 2:
输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3
LeetCode链接:https://leetcode.cn/problems/number-of-islands/description/
开始思路
递归查找当前区域的上下左右,如果有连接的岛屿,就继续递归查找,为了防止重复查找,使用island数组,给不同的岛屿不同的id,并将查找过的海域标记。
/*
整体思路:
1、递归查找,每次传入:map:岛屿starX:下次查找的x坐标starY:下次查找的Y坐标flag:岛屿的标识2、island中不同的岛屿用不同的数字标示:0:未被查找0<i:第i个岛屿,且已被查找-1:此处为海水3、结束条件:island中不存在未被查找的区域 -> return当前区域为海,或者已被访问 -> return当前区域四面环海 -> flag++*/class Solution {
private:int m, n;vector<vector<int>> island;int moveStep[4][2] = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}};int set[1][2] = {{0, 0}};//岛屿是否被查找过bool isFind(int x, int y) {if (island[x][y] == 0)return false;return true;}//是否所有区域都被查找了bool isAllFind() {for (int i = 0; i < island.size(); i++) {for (int j = 0; j < island[i].size(); j++) {if (0 == island[i][j])return false;}}return true;}//当前坐标是否在海域内bool inLand(int x, int y) { return 0 <= x && x < m && 0 <= y && y < n; }//当前岛屿是否已经被完全搜索bool landEnd(int x, int y) {int _x;int _y;for (int i = 0; i < 4; i++) {_x = x + moveStep[i][0];_y = y + moveStep[i][1];if (inLand(_x, _y) && (0 == island[_x][_y])) {return false;}}return true;}//返回被没有查找到的岛屿的起始坐标bool newLand(vector<vector<char>>& map) {for (int i = 0; i < island.size(); i++) {for (int j = 0; j < island[i].size(); j++) {if (!isFind(i, j) && '1' == map[i][j]) {set[0][0] = i;set[0][1] = j;return true;}}}return false;}//递归的查找岛屿void findIsland(vector<vector<char>>& map, int starX, int starY, int flag) {int _x, _y;if (isAllFind()) {return;}if (isFind(starX, starY)) {return;}if (inLand(starX, starY) && 0 == island[starX][starY]) {if ('0' == map[starX][starY]) {island[starX][starY] = -1;return;}island[starX][starY] = flag;}for (int i = 0; i < 4; i++) {_x = starX + moveStep[i][0];_y = starY + moveStep[i][1];if (inLand(_x, _y) && 0 == island[_x][_y]) {// island[_x][_y] = flag;findIsland(map, _x, _y, flag);}}if (landEnd(starX, starY)) {if (newLand(map)) {findIsland(map, set[0][0], set[0][1], flag+1);}}}public:int numIslands(vector<vector<char>>& grid) {int islandNum = 0;m = grid.size();if (m == 0) {return 0;}n = grid[0].size();island = vector<vector<int>>(m, (vector<int>(n, 0)));//从岛屿开始newLand(grid);findIsland(grid, set[0][0], set[0][1], 1);//岛屿中flag最大值为所有岛屿数for (int i = 0; i < island.size(); i++) {for (int j = 0; j < island[i].size(); j++) {if (islandNum < island[i][j])islandNum = island[i][j];}}return islandNum;}
};
不过该方法存在错误,仅通过部分测试用例:
解题思路
开始想复杂了,其实可以分为两步:1、找到未被访问的岛屿;2、遍历岛屿全部陆地。然后遍历地图全部区域即可。
class Solution {
private:int Row, Col, landNum = 0;int moveStep[4][2] = {{1, 0}, {0, 1}, {0, -1}, {-1, 0}};vector<vector<bool>> isVisit;//是否在地图内bool inLand(int k, int l) {if (k < 0 || k >= Row)return false;if (l < 0 || l >= Col)return false;return true;}//标记当前岛屿全部陆地void findLand(vector<vector<char>>& grid, int X, int Y) {int _x, _y;isVisit[X][Y] = true;for (int i = 0; i < 4; i++) {if (inLand(X + moveStep[i][0], Y + moveStep[i][1]) &&!isVisit[X + moveStep[i][0]][Y + moveStep[i][1]] &&(grid[X + moveStep[i][0]][Y + moveStep[i][1]] == '1')) {findLand(grid, X + moveStep[i][0], Y + moveStep[i][1]);}}}public:int numIslands(vector<vector<char>>& grid) {Row = grid.size();if (0 == Row) {cout << "Row is NULL";return 0;}Col = grid[Row - 1].size();//是否被访问过isVisit = vector<vector<bool>>(Row, (vector<bool>(Col, false)));//遍历全部for (int i = 0; i < Row; i++)for (int j = 0; j < Col; j++)//如果当前是岛屿,且没有被访问过if (!isVisit[i][j] && (grid[i][j] == '1')) {//岛屿数量加一;landNum++;//遍历岛屿全部陆地findLand(grid, i, j);}return landNum;}
};
代码运行结果: