200. 岛屿数量

226 阅读4分钟

思路

“岛屿”即为练成一片的‘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);
            }
        }
    }
}

错误: 忘记标记访问过的元素 image.png

错误: 未及时标记 image.png