思路
“岛屿”即为练成一片的‘1’,我们要找出有几个“一片”,即用搜索的方法。 可以用DFS\BFS。
方法一:DFS
思路:
-
把矩阵扫一遍,每找到一个为1的格子,计数+1。
-
对每个为1的格子,搜索它的上下左右格子, 直到:
- 超出边界
- 搜到的格子不再为1
- 访问过的格子要置为2,避免重复访问 或者用一个数组标记是否访问过,这样不用改原数组。
-
然后继续扫到下一个格子。
不修改原数组
class Solution {
// without modifying original array
public int numIslands(char[][] grid) {
int res = 0;
boolean[][] visited = new boolean[grid.length][grid[0].length];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
// 不修改原数组
if (grid[i][j] == '1' && !visited[i][j]) {
res++;
dfs(grid, i, j, visited);
}
}
}
return res;
}
public void dfs(char[][] grid, int i, int j, boolean[][] visited) {
if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) {
return;
}
if (grid[i][j] != '1' || visited[i][j]) {
return;
}
visited[i][j] = true;
dfs(grid, i + 1, j, visited);
dfs(grid, i - 1, j, visited);
dfs(grid, i, j + 1, visited);
dfs(grid, i, j - 1, visited);
}
}
修改原数组
class Solution {
public int numIslands(char[][] grid) {
int length = grid[0].length;
int width = grid.length;
int res = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < length; j++) {
if (grid[i][j] == '1') {
res++;
//找到了一个为1的格子,通过dfs把上下左右相连的格子都置为2,置为2的话如果想复原原数组,可以再遍历复原,置为0就找不回来了
dfs(i, j, grid);
}
}
}
return res;
}
public void dfs(int i, int j, char[][] grid) {
//注意这里是 >=
if (i >= grid.length || j >= grid[0].length || i < 0 || j < 0 || grid[i][j] != '1') {
return;
}
grid[i][j] = '2';//访问过的格子,设为2,防止重复遍历
dfs(i + 1, j, grid);//下
dfs(i - 1, j, grid);//上
dfs(i, j + 1, grid);//右
dfs(i, j - 1, grid);//左
}
}
方法二:BFS
思路:
- 把矩阵扫一遍,每找到一个为1的格子,计数+1。
- 对于为1的格子,把它放到队列中,搜索它相邻的格子,如果有为1的,把他们也放到队列中,直到队列为空。然后扫到下一个格子。
1. 用Java的Pair<>表示放到队列中的格子的坐标。
class Solution {
public int numIslands(char[][] grid) {
int length = grid[0].length;
int width = grid.length;
int res = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < length; j++) {
if (grid[i][j] == '1') {
res++;
//找到了一个为1的格子,然后通过bfs把它上下左右相连的1都置为2,置为2的话如果想复原原数组,可以再遍历复原,置为0 就找不回来了
bfs(i, j, grid);
}
}
}
return res;
}
public void bfs(int i, int j, char[][] grid) {
LinkedList<Pair<Integer, Integer> > queue = new LinkedList<>();//
Pair<Integer, Integer> pair = new Pair<>(i, j);//用来存储坐标,或者把坐标转化为一维的
grid[i][j] = '2';//一开始找到的那个为‘1’的格子,置为2
queue.add(pair);
int length = grid[0].length;
int width = grid.length;
while (!queue.isEmpty()) {
Pair<Integer, Integer> curPair = queue.removeFirst();
int curI = curPair.getKey();
int curJ = curPair.getValue();
if (curI + 1 < width && grid[curI + 1][curJ] == '1') {
grid[curI + 1][curJ] = '2';
queue.add(new Pair<>(curI + 1, curJ));
}
if (curI - 1 >= 0 && grid[curI - 1][curJ] == '1') {
grid[curI - 1][curJ] = '2';
queue.add(new Pair<>(curI - 1, curJ));
}
if (curJ + 1 < length && grid[curI][curJ + 1] == '1') {
grid[curI][curJ + 1] = '2';
queue.add(new Pair<>(curI, curJ + 1));
}
if (curJ - 1 >= 0 && grid[curI][curJ - 1] == '1') {
grid[curI][curJ - 1] = '2';
queue.add(new Pair<>(curI, curJ - 1));
}
}
}
}
2. 把二维坐标i,j转化为一维数字。
class Solution {
public int numIslands(char[][] grid) {
int length = grid[0].length;
int width = grid.length;
int res = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < length; j++) {
if (grid[i][j] == '1') {
res++;
//找到了一个为1的格子,然后通过bfs把它上下左右相连的1都置为2
bfs(i, j, grid);
}
}
}
return res;
}
public void bfs(int i, int j, char[][] grid) {
grid[i][j] = '2';//一开始找到的那个为‘1’的格子,置为2,置为2的话如果想复原原数组,可以再遍历复原,置为0 就找不回来了
int length = grid[0].length;
int width = grid.length;
int pos = i * length + j;//把二维坐标转为一维
LinkedList<Integer> queue = new LinkedList<>();//
queue.add(pos);
while (!queue.isEmpty()) {
int curPos = queue.removeFirst();
//把一维坐标解为二维
int curI = curPos / length;//因为j是小于length的
int curJ = curPos % length;
if (curI + 1 < width && grid[curI + 1][curJ] == '1') {
grid[curI + 1][curJ] = '2';
queue.add((curI + 1) * length + curJ);
}
if (curI - 1 >= 0 && grid[curI - 1][curJ] == '1') {
grid[curI - 1][curJ] = '2';
queue.add((curI - 1) * length + curJ);
}
if (curJ + 1 < length && grid[curI][curJ + 1] == '1') {
grid[curI][curJ + 1] = '2';
queue.add(curI * length + curJ + 1);
}
if (curJ - 1 >= 0 && grid[curI][curJ - 1] == '1') {
grid[curI][curJ - 1] = '2';
queue.add(curI * length + curJ - 1);
}
}
}
}
错误: 忘记标记访问过的元素
错误: 未及时标记