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

news2024/11/25 19:24:10

    DFS专题:力扣岛屿问题

开篇

每次做到DFS相关的题目都是直接跳过。蓝桥杯过后痛定思痛,好好学习一下DFS和BFS。先从DFS开始吧。
参考题解:nettee:岛屿类问题的通用解法、DFS 遍历框架

题目链接: 200.岛屿数量
      463.岛屿的周长
      695.岛屿的最大面积
      827.最大人工岛
      1905.统计子岛屿
      1254.统计封闭岛屿的数目
      1568.使陆地分离的最小天数
      1020.飞地的数量
      419.甲板上的军舰
      733.图像渲染

一、岛屿数量

题目链接: 200.岛屿数量

题目描述

在这里插入图片描述

代码思路

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

代码纯享版

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);
    }
}

代码逐行解析版

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搜索,遇到海洋或超出区域的部分,则周长加一;遇到未搜索过的陆地,则标记为搜索过;遇到搜索过的陆地,直接返回。

代码纯享版

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);
    }
}

代码逐行解析版

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来返回计算结果,感觉更高级

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搜索,遇到海洋或超出区域的部分,则周长加一;遇到未搜索过的陆地,则标记为搜索过;遇到搜索过的陆地,直接返回。

代码纯享版

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);

    }
}

代码逐行解析版

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来返回计算面积结果

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的节点,计算其四个方位岛屿的面积。

代码纯享版

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);
    }
}

代码逐行解析版

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.最终统计出子岛屿的数目

代码纯享版

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);
    }
}

代码逐行解析版

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中根据边界判断是否为封闭岛屿即可

代码纯享版

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);
    }
}

代码逐行解析版

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.

代码纯享版

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);
    }
}

代码逐行解析版

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.飞地的数量

题目描述

在这里插入图片描述

代码思路

代码纯享版

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);
    }
}

代码逐行解析版

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);
    }
}

十、图像渲染

题目链接:

题目描述

在这里插入图片描述

代码思路

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

代码纯享版

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);
    }
}

代码逐行解析版

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.图像渲染

题目描述

在这里插入图片描述

代码思路

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

代码纯享版

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);
    }
}

代码逐行解析版

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,而是直接返回原图?
引用力扣中大佬的解释:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1607118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习波士顿房价

流程 数据获取导入需要的包引入文件,查看内容划分训练集和测试集调用模型查看准确率 数据获取 链接&#xff1a;https://pan.baidu.com/s/1deECYRPQFx8h28BvoZcbWw?pwdft5a 提取码&#xff1a;ft5a --来自百度网盘超级会员V1的分享导入需要的包 import pandas as pd imp…

FreeRTOS之动态创建任务与删除任务

1.本文是利用FreeRTOS来动态创建任务和删除任务。主要是使用FreeRTOS的两个API函数&#xff1a;xTaskCreate()和vTaskDelete()。 任务1和任务2是让LED0、LED1闪烁。任务3是当按键按下时删除任务1。 使用动态创建任务时&#xff0c;需要动态的堆中申请任务所需的内存空间&…

Eagle for Mac v1.9.13注册版:强大的图片管理工具

Eagle for Mac是一款专为Mac用户设计的图片管理工具&#xff0c;旨在帮助用户更高效、有序地管理和查找图片资源。 Eagle for Mac v1.9.13注册版下载 Eagle支持多种图片格式&#xff0c;包括JPG、PNG、GIF、SVG、PSD、AI等&#xff0c;无论是矢量图还是位图&#xff0c;都能以清…

软考 系统架构设计师系列知识点之大数据设计理论与实践(11)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之大数据设计理论与实践&#xff08;10&#xff09; 所属章节&#xff1a; 第19章. 大数据架构设计理论与实践 第3节 Lambda架构 19.3.6 Lambda与其它架构模式对比 Lambda架构的诞生离不开很多现有设计思想和架构的铺垫…

ctfhub-ssrf(2)

1.URL Bypass 题目提示:请求的URL中必须包含http://notfound.ctfhub.com&#xff0c;来尝试利用URL的一些特殊地方绕过这个限制吧 打开环境发现URL中必须包含http://notfound.ctfhub.com&#xff0c;先按照之前的经验查看127.0.0.1/flag.php,发现没什么反应&#xff0c;按照题…

excel表格如何筛选重复的内容并单独显示

在处理Excel数据时&#xff0c;遇到大量数据时需要筛选数据中的重复值并单独显示出来&#xff0c;那么此时该如何处理呢&#xff1f;事实上在Excel表格中筛选出重复的内容并单独显示的方法有很多种&#xff0c;以下是其中常用的3种&#xff1a; 方法一&#xff1a;使用条件格式…

每日OJ题_多源BFS①_力扣542. 01 矩阵(多源BFS解决最短路原理)

目录 多源BFS解决最短路算法原理 力扣542. 01 矩阵 解析代码 多源BFS解决最短路算法原理 什么是单源最短路 / 多源最短路&#xff1f; 之前的BFS解决最短路都是解决的单源最短路。 画图来说&#xff0c;单源最短路问题即为&#xff1a; 而对于多源最短路问题: 如何解决此…

全球排名前十的搜索引擎,你猜百度排名在第几位?bing稳居二位!

通常情况下&#xff0c;营销人员在争夺其在线业务的流量时会非常关注Google&#xff0c;无论是通过他们的网站&#xff0c;博客文章还是其他形式的内容。考虑到谷歌无疑是最受欢迎的搜索引擎&#xff0c;拥有超过85%的搜索市场份额&#xff0c;这是有道理的。 但这种受欢迎程度…

STM32使用HAL库解码433遥控芯片EV1527

1、首先了解一下433遥控芯片ev1527的基本资料&#xff1a; 这是他编码的关键信息&#xff1a; 也就是说&#xff0c;一帧数据是&#xff1a;一个同步码20位内码4位按键码。 内码20位2^201048576个地址。 发送就是一帧数据接一帧数据不间断发送。 2、解码思路 从上面的帧结构…

node-mysql数据库的下载与安装

01 mysql数据库的安装 网址&#xff1a;mysql.com/downloads/ 打开之后往下翻 点击 MySQL Community (GPL) Downloads 》 点击 MySRL Community Server 再点击 No thanks,just stant my download. 02 安装mysql 03 安装完成之后检查mysql服务是否开启 services.msc 04 启动…

vue3【详解】 vue3 比 vue2 快的原因

使用 Proxy 实现响应式 vue3使用的 Proxy 在处理属性的读取和写入时&#xff0c;比vue2使用的defineProperty 有更好的性能&#xff08;速度加倍的同时&#xff0c;内存还能减半&#xff01;&#xff09; 更新类型标记 Patch Flag 在编译模板时&#xff08;将vue语法转换为js描…

Seal^_^【送书活动第一期】——《Vue.js+Node.js全栈开发实战(第2版)》

Seal^_^【送书活动第一期】——《Vue.jsNode.js全栈开发实战&#xff08;第2版&#xff09;》 一、参与方式二、本期推荐图书2.1 前 言2.2 作者简介2.3 图书简介2.4 本书特色2.5 编辑推荐2.6 书籍目录 三、正版购买 一、参与方式 1、关注博主的账号。 2、点赞、收藏、评论博主的…

如何判断两个IP地址是否在同一网段?

要判断两个IP地址是否在同一网段&#xff0c;首先需要对IP地址和子网掩码有深入的理解。IP地址是互联网协议地址&#xff0c;用于在IP通信中标识和定位每台设备的逻辑地址。而子网掩码则是一个32位的地址掩码&#xff0c;用于将IP地址划分为网络地址和主机地址两部分。通过比较…

9月BTE第8届广州国际生物技术大会暨展览会,全媒体聚焦下的高精尖行业盛会

政策春风助力&#xff0c;共迎大湾区生物医药行业50亿红利 今年3月“创新药”首次写入国务院政府工作报告之后&#xff0c;广州、珠海、北京多地政府纷纷同步出台了多项细化政策&#xff0c;广州最高支持额度高达50亿元&#xff0c;全链条为生物医药产业提供资金支持&#xff…

【C++】开始了解反向迭代器

送给大家一句话&#xff1a; 重要的东西眼睛是看不到的 — 《小王子》 反向迭代器 1 前言2 反向迭代器3 复刻反向迭代器3.1 加减操作3.2 判断操作3.3 访问操作 4 链表的反向迭代器Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff0…

SQVI创建以及生成程序

SAP数据快速查询工具&#xff1a;Sqvi-QuickView 项目实施&运维阶段&#xff0c;为了快速获取一些透明表数据&#xff0c;一开始接触项目肯定会通过大量的数据表查找&#xff0c;然后线下通过EXCEL通过VLOOKUP进行数据关联&#xff0c;这种方式在关联数据较少的情况比较适应…

【源码】2024新版二开版抢单刷单系统,前端简体、繁体双语言-支持倒计时抢单,后台指定派单连单卡单

CD&#xff1a;获取方式联系小编 微信&#xff1a;uucodes 公众号&#xff1a;资源猿 小编提供资源代找&#xff0c;环境搭建&#xff0c;源码部署调试等业务&#xff0c;需要的可以联系

APP广告变现项目要怎么去做,需要考虑哪些方面!!

要开始一个APP广告变现项目&#xff0c;您可以按照以下步骤进行操作&#xff1a; 制定商业计划&#xff1a;确定您的目标市场、目标受众和变现方式。了解竞争对手和市场趋势&#xff0c;并制定相应的推广策略。 开发APP&#xff1a;找到合适的开发团队或开发者来设计和开发您…

机器学习在安全领域的应用:从大数据中识别潜在安全威胁

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

微纤维眼镜清洁布的革命性进化

在日常生活中&#xff0c;眼镜是许多人不可或缺的日常用品&#xff0c;无论是视力矫正还是防护眼睛免受阳光的伤害。然而&#xff0c;眼镜的清洁常常是一个令人头疼的问题&#xff0c;特别是在面对指纹、灰尘和其他污垢时。传统的清洁方法往往需要化学清洁剂&#xff0c;不仅繁…