DFS专题:力扣岛屿问题(持续更新)

DFS专题:力扣岛屿问题

开篇

每次做到DFS相关的题目都是直接跳过。蓝桥杯过后痛定思痛,好好学习一下DFS和BFS。先从DFS开始吧。

参考题解:nettee:岛屿类问题的通用解法、DFS 遍历框架

题目链接:200.岛屿数量

463.岛屿的周长

695.岛屿的最大面积

827.最大人工岛

1905.统计子岛屿

1254.统计封闭岛屿的数目

1568.使陆地分离的最小天数

1020.飞地的数量

419.甲板上的军舰

733.图像渲染

一、岛屿数量

题目链接:200.岛屿数量

题目描述

代码思路

使用for对每一个网格点进行判断,如果遇到未搜索过的'1',则使岛屿数加一,并利用dfs将与其相连的'1'都进行标记,确保每次搜索到1都是一个新的岛屿。

代码纯享版

java 复制代码
class Solution {
    public int numIslands(char[][] grid) {
        int len = grid.length; 
        int wide = grid[0].length; 
        int sum = 0;
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == '1'){
                    sum++;
                    dfs(grid, i, j);
                }
            }
        }

        return sum;
    }
    void dfs(char[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;
        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != '1'){
            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);
    }
}

代码逐行解析版

java 复制代码
class Solution {
    
    public int numIslands(char[][] grid) {
        int len = grid.length; //岛屿长度
        int wide = grid[0].length; //岛屿宽度
        int sum = 0; //岛屿总数

        //遍历岛屿每一个位置
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){ 
                if(grid[i][j] == '1'){ //如果为陆地
                    sum++; //岛屿总数加一
                    dfs(grid, i, j); //dfs
                }
            }
        }

        return sum;
    }

    //深度搜索所有连接在一起的'1',将其变为'2'
    //grid[i][j] == '0' 水
    //grid[i][j] == '1' 未搜索的陆地
    //grid[i][j] == '2' 已搜索的陆地
    void dfs(char[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        //排除2种情况
        //1.超出网格范围的搜索
        //2.不是未搜索的陆地
        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != '1'){ 
            return;
        }
        grid[i][j] = '2'; //将grid[i][j] == '1'的情况标记为'2'
        //上下左右四个方位的搜索
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);
    }
}

二、岛屿的周长

题目链接:463.岛屿的周长

题目描述

代码思路

利用for循环遍历到一块陆地后,对这块陆地进行dfs搜索,遇到海洋或超出区域的部分,则周长加一;遇到未搜索过的陆地,则标记为搜索过;遇到搜索过的陆地,直接返回。

代码纯享版

java 复制代码
class Solution {

    public int area = 0;

    public int islandPerimeter(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        

        int i = 0, j = 0;
        int judge = 1;
        for(i = 0; i < len; i++){
            for(j = 0; j < wide; j++){
                if(grid[i][j] == 1){
                    dfs(grid, i , j);
                    return area;
                }
            }
            
        }
        
        return 0;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] == 0){
            area++;
            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);
    }
}

代码逐行解析版

java 复制代码
class Solution {

    public int area = 0; //设周长为公共变量

    public int islandPerimeter(int[][] grid) {
        int len = grid.length; 
        int wide = grid[0].length;
        
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){ //碰到陆地,进行dfs
                    dfs(grid, i , j); 
                    return area; //只有一块岛屿,所以搜索一次后即可返回周长
                }
            }
            
        }
        
        return 0; //没找到岛屿,返回0
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        //由题目图可知,搜索到超出区域范围或海洋位置的,周长加一
        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] == 0){ 
            area++;
            return;
        }
        if(grid[i][j] == 2){ //已搜索过的直接返回
            return;
        }
        
        grid[i][j] = 2; //把未搜索过的陆地标记为2:已搜索过的陆地

        //对上下左右进行搜索
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }
}

大佬相似题解

主要区别是没有设置周长变量为公共变量,而是在递归中用return来返回计算结果,感觉更高级

java 复制代码
public int islandPerimeter(int[][] grid) {
    for (int r = 0; r < grid.length; r++) {
        for (int c = 0; c < grid[0].length; c++) {
            if (grid[r][c] == 1) {
                // 题目限制只有一个岛屿,计算一个即可
                return dfs(grid, r, c);
            }
        }
    }
    return 0;
}

int dfs(int[][] grid, int r, int c) {
    // 函数因为「坐标 (r, c) 超出网格范围」返回,对应一条黄色的边
    if (!inArea(grid, r, c)) {
        return 1;
    }
    // 函数因为「当前格子是海洋格子」返回,对应一条蓝色的边
    if (grid[r][c] == 0) {
        return 1;
    }
    // 函数因为「当前格子是已遍历的陆地格子」返回,和周长没关系
    if (grid[r][c] != 1) {
        return 0;
    }
    grid[r][c] = 2;
    return dfs(grid, r - 1, c)
        + dfs(grid, r + 1, c)
        + dfs(grid, r, c - 1)
        + dfs(grid, r, c + 1);
}

// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
    return 0 <= r && r < grid.length 
        	&& 0 <= c && c < grid[0].length;
}

三、岛屿的最大面积

题目链接:695.岛屿的最大面积

题目描述

代码思路

利用for循环遍历到一块陆地后,对这块陆地进行dfs搜索,遇到海洋或超出区域的部分,则周长加一;遇到未搜索过的陆地,则标记为搜索过;遇到搜索过的陆地,直接返回。

代码纯享版

java 复制代码
class Solution {

    public int area = 0;

    public int maxAreaOfIsland(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int max = 0; 

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){
                    dfs(grid, i, j);
                    max = Math.max(max, area);
                    area = 0;
                }
            }
        }

        return max;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 1){
            return;
        }

        area++;
        grid[i][j] = 2;
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);

    }
}

代码逐行解析版

java 复制代码
class Solution {

    public int area = 0; //设岛屿的面积为公共变量

    public int maxAreaOfIsland(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int max = 0; //用来统计岛屿最大面积

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){ //遍历每一个单元格
                if(grid[i][j] == 1){ //遇到土地
                    dfs(grid, i, j); //进行dfs
                    max = Math.max(max, area); //获取岛屿面积最大值
                    area = 0; //将area重新设为0,方便下一块岛屿面积的计算
                }
            }
        }

        return max; //返回岛屿面积最大值
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        //遇到超出的区域或水,直接返回
        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 1){
            return;
        }

        area++; //面积加一
        grid[i][j] = 2; //标记为搜索过

        //对上下左右区域进行搜索
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);

    }
}

大佬相似题解

主要区别是没有设置周长变量为公共变量,而是在递归中用return来返回计算面积结果

java 复制代码
public int maxAreaOfIsland(int[][] grid) {
    int res = 0;
    for (int r = 0; r < grid.length; r++) {
        for (int c = 0; c < grid[0].length; c++) {
            if (grid[r][c] == 1) {
                int a = area(grid, r, c);
                res = Math.max(res, a);
            }
        }
    }
    return res;
}

int area(int[][] grid, int r, int c) {
    if (!inArea(grid, r, c)) {
        return 0;
    }
    if (grid[r][c] != 1) {
        return 0;
    }
    grid[r][c] = 2;
    
    return 1 
        + area(grid, r - 1, c)
        + area(grid, r + 1, c)
        + area(grid, r, c - 1)
        + area(grid, r, c + 1);
}

boolean inArea(int[][] grid, int r, int c) {
    return 0 <= r && r < grid.length 
        	&& 0 <= c && c < grid[0].length;
}

四、最大人工岛

题目链接:827.最大人工岛

题目描述

代码思路

这道题作为困难题,比前面三道复杂一点,要进行两次搜索。第一次是利用dfs,统计每一块岛屿的面积。第二次是寻找为0的节点,计算其四个方位岛屿的面积。

代码纯享版

java 复制代码
class Solution {

    public static int area = 0; //面积
    public static Map<Integer, Integer> map = new HashMap(); //记录每块岛屿记号及对应面积
    public static int sign = 2; //从2开始标记

    public int largestIsland(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int max = 0;

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){
                    dfs(grid, i, j);
                    map.put(sign, area);
                    sign++;
                    area = 0;
                }
            }
        }

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 0){
                    Set<Integer> set = new HashSet();
                    if(i + 1 < len){
                        area += map.getOrDefault(grid[i + 1][j], 0);
                        set.add(grid[i + 1][j]);    
                    }
                    if(i - 1 >= 0 && !set.contains(grid[i - 1][j])){
                        area += map.getOrDefault(grid[i - 1][j], 0);
                        set.add(grid[i - 1][j]);
                    }
                    if(j + 1 < wide && !set.contains(grid[i][j + 1])){
                        area += map.getOrDefault(grid[i][j + 1], 0);
                        set.add(grid[i][j + 1]);
                    }
                    if(j - 1 >= 0 && !set.contains(grid[i][j - 1])){
                        area += map.getOrDefault(grid[i][j - 1], 0);
                        set.add(grid[i][j - 1]);
                    }
                    max = Math.max(max, area + 1);
                    area = 0;
                }
            }
        }
        
        return max == 0 ? len * wide : max;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 1){
            return;
        }

        area++;
        grid[i][j] = sign;
        dfs(grid, i + 1, j);
        dfs(grid, i - 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }
}

代码逐行解析版

java 复制代码
class Solution {

    public static int area = 0; //面积
    public static Map<Integer, Integer> map = new HashMap(); //记录每块岛屿记号及对应面积
    public static int sign = 2; //从2开始标记

    public int largestIsland(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int max = 0; //记录面积最大值

        //第一步:利用dfs统计每一块岛屿的面积
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){ //遍历每一个点
                if(grid[i][j] == 1){ //遇到岛屿点
                    dfs(grid, i, j); //通过dfs计算岛屿面积
                    map.put(sign, area); //用map来标记岛屿序号并记录对应面积
                    sign++;
                    area = 0; //将面积变成0,方便下一个岛屿面积的统计
                }
            }
        }

        //第二步:找到每一个为0的点,计算其上下左右四个方位的岛屿面积和
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 0){ //遇到为0的点
                    Set<Integer> set = new HashSet(); //利用集合防止重复计算同一片岛屿

                    //对四个方向的岛屿面积进行相加
                    if(i + 1 < len){
                        area += map.getOrDefault(grid[i + 1][j], 0);
                        set.add(grid[i + 1][j]);    
                    }
                    if(i - 1 >= 0 && !set.contains(grid[i - 1][j])){
                        area += map.getOrDefault(grid[i - 1][j], 0);
                        set.add(grid[i - 1][j]);
                    }
                    if(j + 1 < wide && !set.contains(grid[i][j + 1])){
                        area += map.getOrDefault(grid[i][j + 1], 0);
                        set.add(grid[i][j + 1]);
                    }
                    if(j - 1 >= 0 && !set.contains(grid[i][j - 1])){
                        area += map.getOrDefault(grid[i][j - 1], 0);
                        set.add(grid[i][j - 1]);
                    }
                    max = Math.max(max, area + 1); //取最大值,area+1的加一是将grid[i][j]=0变成1
                    area = 0;
                }
            }
        }
        //如果找不到为0的单元格,证明该矩阵全部都是1,直接返回矩阵面积,否则返回max
        return max == 0 ? len * wide : max; 
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        //排除超出区域的情况和已统计过的情况
        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 1){ 
            return;
        }

        area++; //面积加一
        grid[i][j] = sign; //标记岛屿记号,也使其被标记为统计过
        //上下左右四个方位进行搜索
        dfs(grid, i + 1, j);
        dfs(grid, i - 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }
}

五、统计子岛屿

题目链接:1905.统计子岛屿

题目描述

代码思路

一共两个步骤:第一次for循环利用dfs将grid2的每一块岛屿进行标记并计算总岛屿数目sum;第二次for循环同时将grid1和grid2进行遍历,如果发现未完全包含的岛屿,则令sum-1.最终统计出子岛屿的数目

代码纯享版

java 复制代码
class Solution {

    public static int sign = 2; //标记岛屿序号

    public int countSubIslands(int[][] grid1, int[][] grid2) {
        int len = grid2.length;
        int wide = grid2[0].length;
        int sum = 0;

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid2[i][j] == 1){
                    dfs(grid2, i, j);
                    sum++;
                    sign++;
                }
            }
        }
        
        Set<Integer> set = new HashSet();
        set.add(0);
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(!set.contains(grid2[i][j]) && grid1[i][j] == 0){
                    set.add(grid2[i][j]);
                    sum--;
                }
            }
        }

        return sum;
    }

    void dfs(int[][] grid2, int i, int j){
        int len = grid2.length;
        int wide = grid2[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid2[i][j] != 1){
            return;
        }

        grid2[i][j] = sign;
        dfs(grid2, i + 1, j);
        dfs(grid2, i - 1, j);
        dfs(grid2, i, j + 1);
        dfs(grid2, i, j - 1);
    }
}

代码逐行解析版

java 复制代码
class Solution {

    public static int sign = 2; //标记岛屿序号

    public int countSubIslands(int[][] grid1, int[][] grid2) {
        int len = grid2.length;
        int wide = grid2[0].length;
        int sum = 0; //统计子岛屿数量

        //第一步:标记grid2中的每块岛屿并计算grid2中岛屿数量
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){ //遍历grid2的点
                if(grid2[i][j] == 1){ //遇到陆地
                    dfs(grid2, i, j); //利用dfs搜索该陆地所在的整个岛屿
                    sum++; //先算出grid2中岛屿的数量
                    sign++;
                }
            }
        }
        
        //同时对grid1和grid2的点进行遍历,判断有多少不重合
        Set<Integer> set = new HashSet(); //区分哪些点需要遍历,set集合中存在的点:0和已发现没有完全包含的岛屿序号
        set.add(0); //0点不需遍历
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(!set.contains(grid2[i][j]) && grid1[i][j] == 0){ //发现新的未完全包含的岛屿序号
                    set.add(grid2[i][j]); //添加到set集合
                    sum--; //子岛屿数量减一
                }
            }
        }

        return sum; //返回子岛屿数量
    }

    void dfs(int[][] grid2, int i, int j){
        int len = grid2.length;
        int wide = grid2[0].length;

        //排除超出区域的情况和已搜索过的点
        if(i < 0 || i >= len || j < 0 || j >= wide || grid2[i][j] != 1){ 
            return;
        }

        grid2[i][j] = sign; //标记该点所在岛屿点序号
        //对该点四个方位进行搜索
        dfs(grid2, i + 1, j);
        dfs(grid2, i - 1, j);
        dfs(grid2, i, j + 1);
        dfs(grid2, i, j - 1);
    }
}

六、统计封闭岛屿的数目

题目链接:1254.统计封闭岛屿的数目

题目描述

代码思路

这道题和核心点:陆地的边界不是搜索区域边界,而是水。所以在dfs中根据边界判断是否为封闭岛屿即可

代码纯享版

java 复制代码
class Solution {

    public static int judge = 1;

    public int closedIsland(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int sum = 0;

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 0){
                    dfs(grid, i, j);
                    sum += judge;
                    judge = 1;
                }
            }
        }

        return sum;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide){
            judge = 0;
            return;
        }
        if(grid[i][j] != 0){
            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);
    }
}

代码逐行解析版

java 复制代码
class Solution {

    public static int judge = 1; //用于判断是否是封闭岛屿,1是,0不是

    public int closedIsland(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int sum = 0; //统计封闭岛屿数量

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 0){ //遇到土地(与前面题目相反,这道题土地上0,水是1)
                    dfs(grid, i, j); //dfs判断是否为封闭岛屿
                    sum += judge; //将judge设置为0或1,便于统计数目,不需要额外的判断
                    judge = 1; //将judge还原为1
                }
            }
        }

        return sum; //返回封闭岛屿数目
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide){ //遇到超出区域的,都不是封闭岛屿
            judge = 0;
            return;
        }
        if(grid[i][j] != 0){ //遇到水(1)或搜索过(2)直接返回
            return;
        }

        grid[i][j] = 2; //将grid[i][j]==0的点设置为2
        //对该点四个方位进行搜索
        dfs(grid, i + 1, j);
        dfs(grid, i - 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }
}

七、使陆地分离的最小天数

题目链接:1568.使陆地分离的最小天数

题目描述

代码思路

这道题思考后会发现只有0,1,2三种答案。先统计岛屿个数,若大于1,则答案为0;若岛屿个数小于等于1且面积小于等于2,则答案为岛屿面积。排除上述情况后,则遍历判断是否能只修改一个陆地实现隔离的效果,可以返回1,否则返回2.

代码纯享版

java 复制代码
class Solution {

    public int num = 0; //岛屿的面积
    public int num_part = 0; //分离一次后岛屿的面积

    public int minDays(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int sum = 0;

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){
                    sum++;
                    if(sum == 2) return 0;
                    dfs(grid, i, j);
                }
            }
        }

        if(num <= 2) return num;
        else{
            for(int i = 0; i < len; i++){
                for(int j = 0; j < wide; j++){
                    if(grid[i][j] == 2){
                        grid[i][j] = 0;
                        if(separation(grid) == true) return 1;
                        grid[i][j] = 2;
                    }
                }
            }
        }
        return 2;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 1){
            return;
        }

        num++;
        grid[i][j] = 2;
        dfs(grid, i + 1, j);
        dfs(grid, i - 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }

    Boolean separation(int[][] grid){
        int len = grid.length;
        int wide = grid[0].length;

        int judge = 1;

        for(int i = 0; i < len; i++){
                for(int j = 0; j < wide; j++){
                    if(grid[i][j] == 2){
                        dfs2(grid, i, j);
                        if(num_part != num - 1) return true;
                        else{
                            judge = 0;
                            num_part = 0;
                            for(int k = 0; k < len; k++){
                                for(int l = 0; l < wide; l++){
                                    if(grid[k][l] == 3) grid[k][l] = 2;
                                }
                            }
                            break;
                        }
                    }
                    if(judge == 0) break;
                }
        }
        return false;
    }

    void dfs2(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 2){
            return;
        }

        num_part++;
        grid[i][j] = 3;
        dfs2(grid, i + 1, j);
        dfs2(grid, i - 1, j);
        dfs2(grid, i, j + 1);
        dfs2(grid, i, j - 1);
    }
}

代码逐行解析版

java 复制代码
class Solution {

    public int num = 0; //岛屿的面积
    public int num_part = 0; //分离一次后岛屿的面积

    public int minDays(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int sum = 0;

        //统计岛屿的个数和岛屿的面积
        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){
                    sum++;
                    if(sum == 2) return 0; //个数为2,直接返回
                    dfs(grid, i, j); //dfs计算岛屿面积
                }
            }
        }

        //此时已确定岛屿只有一个

        if(num <= 2) return num;  //若岛屿面积小于等于2,只能全部改为水

        //判断只更改一个陆地能否实现隔离(陆地为2,水为0)
        else{
            for(int i = 0; i < len; i++){
                for(int j = 0; j < wide; j++){
                    if(grid[i][j] == 2){
                        grid[i][j] = 0; //将一块陆地更改为水
                        if(separation(grid) == true) return 1; //单独使用separation方法来判断,如果成功,返回1
                        grid[i][j] = 2;
                    }
                }
            }
        }
        return 2; //发现不能只更改1个陆地,只能返回2
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 1){
            return;
        }

        num++;
        grid[i][j] = 2;
        dfs(grid, i + 1, j);
        dfs(grid, i - 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
    }

    Boolean separation(int[][] grid){
        int len = grid.length;
        int wide = grid[0].length;

        int judge = 1; //一次更改只需判断判断一次即可,用judge方便退出双层循环

        for(int i = 0; i < len; i++){
                for(int j = 0; j < wide; j++){
                    if(grid[i][j] == 2){
                        dfs2(grid, i, j);//利用dfs2搜索看是否完成隔离
                        if(num_part != num - 1) return true; //两者不相等说明实现隔离,返回true

                        //将grid数组、num_part恢复到搜索前到样子,方便下一次搜索
                        else{
                            judge = 0;
                            num_part = 0;
                            for(int k = 0; k < len; k++){
                                for(int l = 0; l < wide; l++){
                                    if(grid[k][l] == 3) grid[k][l] = 2;
                                }
                            }
                            break;
                        }
                    }
                    if(judge == 0) break; 
                }
        }
        return false; 
    }

    void dfs2(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || grid[i][j] != 2){
            return;
        }

        num_part++;
        grid[i][j] = 3;
        dfs2(grid, i + 1, j);
        dfs2(grid, i - 1, j);
        dfs2(grid, i, j + 1);
        dfs2(grid, i, j - 1);
    }
}

八、飞地的数量

题目链接:1020.飞地的数量

题目描述

代码思路

代码纯享版

java 复制代码
class Solution {

    public int judge = 1; //搭配陆地是否接触网格边界,1:接触;0:不接触
    public int area = 0; //每块陆地的单元格数量

    public int numEnclaves(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int sum = 0; //满足要求的单元格数量

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){
                    dfs(grid, i, j);
                    sum += judge == 1 ? area : 0;
                    judge = 1;
                    area = 0;
                }
            }
        }
        return sum;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide){
            judge = 0;
            return;
        }
        if(grid[i][j] != 1) return;

        grid[i][j] = 2;
        area++;
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);
    }
}

代码逐行解析版

java 复制代码
class Solution {

    public int judge = 1; //搭配陆地是否接触网格边界,1:接触;0:不接触
    public int area = 0; //每块陆地的单元格数量

    public int numEnclaves(int[][] grid) {
        int len = grid.length;
        int wide = grid[0].length;
        int sum = 0; //满足要求的单元格总数

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(grid[i][j] == 1){ //遇到陆地
                    dfs(grid, i, j); //运用dfs,判断是否接触网格边界,并计算该陆地的单元格数量
                    sum += judge == 1 ? area : 0; //为1时满足题目条件,将陆地单员格加到sum中

                    //恢复judge和area
                    judge = 1; 
                    area = 0;
                }
            }
        }
        return sum;
    }

    void dfs(int[][] grid, int i, int j){
        int len = grid.length;
        int wide = grid[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide){ //接触了网格边界,judge变成0
            judge = 0;
            return;
        }
        if(grid[i][j] != 1) return; //不是1时,为海洋或遍历过的陆地

        grid[i][j] = 2; //标记为遍历过
        area++; //该陆地的单元格加1

        //遍历该单元格四个方位
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);
    }
}

十、图像渲染

题目链接:

题目描述

代码思路

简单模版题,每次遇到军舰加一即可

代码纯享版

java 复制代码
class Solution {
    public int countBattleships(char[][] board) {
        int len = board.length;
        int wide = board[0].length;
        int sum = 0;

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(board[i][j] == 'X'){
                    sum++;
                    dfs(board, i, j);
                }
            }
        }

        return sum;
    }

    void dfs(char[][] board, int i, int j){
        int len = board.length;
        int wide = board[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || board[i][j] != 'X'){
            return;
        }

        board[i][j] = '0';
        dfs(board, i + 1, j);
        dfs(board, i - i, j);
        dfs(board, i, j + 1);
        dfs(board, i, j - 1);
    }
}

代码逐行解析版

java 复制代码
class Solution {
    public int countBattleships(char[][] board) {
        int len = board.length;
        int wide = board[0].length;
        int sum = 0; //统计战舰的数量

        for(int i = 0; i < len; i++){
            for(int j = 0; j < wide; j++){
                if(board[i][j] == 'X'){ //遇到战舰
                    sum++; //数量加一
                    dfs(board, i, j); //dfs搜索整只战舰
                }
            }
        }

        return sum; //返回战舰的数量
    }

    void dfs(char[][] board, int i, int j){
        int len = board.length;
        int wide = board[0].length;

        if(i < 0 || i >= len || j < 0 || j >= wide || board[i][j] != 'X'){ //排除超出范围的区域和'.'区域
            return;
        }

        board[i][j] = '0'; //标记为搜索过

        //搜索该位置的四个方位
        dfs(board, i + 1, j);
        dfs(board, i - i, j);
        dfs(board, i, j + 1);
        dfs(board, i, j - 1);
    }
}

十、图像渲染

题目链接:733.图像渲染

题目描述

代码思路

从给定的起点开始,进行深度优先搜索。每次搜索到一个方格时,如果其与初始位置的方格颜色相同,就将该方格的颜色更新。注意:因为初始位置的颜色会被修改,所以我们需要保存初始位置的颜色,以便于之后的更新操作。

代码纯享版

java 复制代码
class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {
        if(image[sr][sc] != color){
            dfs(image, sr, sc, color, image[sr][sc]);
        }
        return image;
    }

    void dfs(int[][] image, int i, int j, int color, int firstcolor){
        int len = image.length;
        int wide = image[0].length;

        if(i < 0 || i >= len || j < 0 || j >=wide || image[i][j] != firstcolor){
            return;
        }
        image[i][j] = color;

        dfs(image, i + 1, j, color, firstcolor);
        dfs(image, i - 1, j, color, firstcolor);
        dfs(image, i, j + 1, color, firstcolor);
        dfs(image, i, j - 1, color, firstcolor);
    }
}

代码逐行解析版

java 复制代码
class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {
        if(image[sr][sc] != color){  //起始颜色和目标颜色相同,直接返回原图,不需dfs。具体解释看代码问题的回答
            dfs(image, sr, sc, color, image[sr][sc]);
        }
        return image;
    }
    //color是修改后的颜色,firstcolor是初始像素的颜色
    void dfs(int[][] image, int i, int j, int color, int firstcolor){ 
        int len = image.length;
        int wide = image[0].length;

        //排除超出区域的情况和无需修改的区域
        if(i < 0 || i >= len || j < 0 || j >=wide || image[i][j] != firstcolor){ 
            return;
        }
        image[i][j] = color; //修改颜色

        dfs(image, i + 1, j, color, firstcolor);
        dfs(image, i - 1, j, color, firstcolor);
        dfs(image, i, j + 1, color, firstcolor);
        dfs(image, i, j - 1, color, firstcolor);
    }
}

代码有关问题的解释

为什么要在起始颜色和目标颜色相同时,不进行dfs,而是直接返回原图?

引用力扣中大佬的解释:

相关推荐
逆水寻舟2 小时前
算法学习记录2
python·学习·算法
羞儿2 小时前
【读点论文】基于二维伽马函数的光照不均匀图像自适应校正算法
人工智能·算法·计算机视觉
青衫酒1453 小时前
中国剩余定理
算法
鸽鸽程序猿3 小时前
【数据结构】顺序表
java·开发语言·数据结构·学习·算法·intellij idea
Chris-zz3 小时前
C++:继承
开发语言·c++·算法·学习方法
硕风和炜3 小时前
【LeetCode:3033. 修改矩阵 + 模拟】
java·算法·leetcode·矩阵·模拟
取加若则_4 小时前
C++入门(C语言过渡)
c语言·开发语言·数据结构·c++·算法
真果粒wrdms4 小时前
【在线词典】项目实现
linux·c语言·嵌入式硬件·算法·udp·sqlite3
YangZheng@4 小时前
23种设计模式
c++·算法·设计模式
当年拼却醉颜红4 小时前
力扣爆刷第161天之TOP100五连刷71-75(搜索二叉树、二维矩阵、路径总和)
算法·leetcode·矩阵