BFS解决floodfill算法题目练习

BFS解决floodfill算法

图像渲染

题目解析 :就是将与起始位置相同颜色相同并且连通 (上下左右)的位置颜色修改成color(指定颜色)
思想 :从起始位置开始不断递归上下左右方向 ,将与其颜色相同位置修改颜色,并且从这个修改的位置上下左右与起始颜色相同位置也要修改 ,就这样不断修改,直到连通区域都修改完成就结束了

细节问题:

此时这里可能修改前后颜色一样,此时这种情况直接返回即可(防止死递归)

java 复制代码
class Solution {
    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    int m,n;
    int begin;//要修改颜色
    int end;//修改成的颜色
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {    
        m = image.length;
        n = image[0].length;
        begin = image[sr][sc];
        end = color;
        //如果要修改的和修改后的一样直接返回即可
        if(image[sr][sc] == color){
            return image;
        }


        //从sr,sc开始找
        dfs(image,sr,sc);
        image[sr][sc] = color;
        return image;
    }

    public void dfs(int[][] image,int sr,int sc){

        for(int k = 0;k < 4;k++){
            int x = sr + dx[k];
            int y = sc + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && image[x][y] == begin){
                image[x][y] = end;
                dfs(image,x,y);//下一层
            }
        }
    }
}

岛屿数量

题目解析 :就是找出岛屿数量(1的连通块的数量)
思想:从1岛屿开始标记其所在连通块,防止重复统计

java 复制代码
class Solution {
    int ret;
    int m,n;
    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    boolean[][] visited;//标记已经遍历过的位置
    public int numIslands(char[][] grid) {
        //直接从边界出发即可
        m = grid.length;
        n = grid[0].length;
        visited =  new boolean[m][n];
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(visited[i][j] == false && grid[i][j] == '1'){
                    ret++;
                    dfs(grid,i,j);
                }
            }
        }
        return ret;
    }
    public void dfs(char[][] grid,int i,int j){
        for(int k = 0; k < 4;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && visited[x][y] == false && grid[x][y] == '1'){
                visited[x][y] = true;
                dfs(grid,x,y);
            }
        }
    }
}

岛屿的最大面积

题目解析 :有很多个岛屿,求出最大岛屿面积(这个岛屿1的数量)
思想 :每次从一个未走过的1开始一个新的岛屿

可以使用一个全局 count 统计此时岛屿数量即可

java 复制代码
class Solution {
    int ret;
    int count;
    int m,n;
    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    boolean[][] visited;
    public int maxAreaOfIsland(int[][] grid) {
        m = grid.length;
        n = grid[0].length;

        visited = new boolean[m][n];

        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(visited[i][j] == false && grid[i][j] == 1){
                    visited[i][j] = true;
                    count++;
                    dfs(grid,i,j);
                    //更新结果
                    ret = Math.max(ret,count);
                    count = 0;
                }
            }
        }
        return ret;
    }
    public void dfs(int[][] grid,int i,int j){
       

        for(int k = 0;k < 4;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && visited[x][y] == false && grid[x][y] == 1){
                visited[x][y] = true;
                count++;
                dfs(grid,x,y);
                 
            }
        }
    }
}

被围绕的区域

题目解析 :将被X完全围住的O修改成X,未被完全围住O不修改
思想 :正难则反,由于里面的O存在不是被X围住的不可以修改

先将这些未被围住的O修改成 ' . ',最后剩余的被围住的O,将剩余O修改成X,将 ' . '修改回来

java 复制代码
class Solution {
    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    int m,n;
    public void solve(char[][] board) {
        m = board.length;
        n = board[0].length;

        //1. 将与边界相邻的O(未被围住的)修改 .
        for(int i = 0;i < m;i++){
            if(board[i][0] == 'O'){
                board[i][0] = '.';
                dfs(board,i,0);
            }
            if(board[i][n-1] == 'O'){
                board[i][n-1] = '.';
                dfs(board,i,n-1);
            }
        } 

        for(int i = 0; i < n;i++){
            if(board[0][i] == 'O'){
                board[0][i] = '.';
                dfs(board,0,i);
            }
            if(board[m-1][i] == 'O'){
                board[m-1][i] = '.';
                dfs(board,m-1,i);
            }
        }

        //2.最后将.修改成O
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(board[i][j] == 'O'){
                    board[i][j] = 'X';
                }else if(board[i][j] == '.'){
                    board[i][j] = 'O';
                }
            }
        }
    }
    //将未被X围住的O修改成.
    public void dfs(char[][] board,int i,int j){

        for(int k = 0;k < 4;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O'){
                board[x][y] = '.';
                dfs(board,x,y);
            }
        }
    }
}

太平洋大西洋水流问题

题目解析 :水往低处流,找出所有既可以流向太平洋又可以流向大西洋的位置
思想 :使用两个标记数组,标记可以流向那个海洋,最后将都可以流向的位置进行通统计返回即可

从边界开始进行扩展,扩展比当前高的位置,高的位置可以向下流,不断以对应边界为起点进行扩展

java 复制代码
class Solution {
    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    int m,n;

    public List<List<Integer>> pacificAtlantic(int[][] heights) {
        m = heights.length;
        n = heights[0].length;
        boolean[][] pac = new boolean[m][n];
        boolean[][] atl = new boolean[m][n];

        List<List<Integer>> ret = new ArrayList<>();
        //从大西洋和太平洋开始找可以流向它的位置
        //都可以流向的位置就是要找的结果

        //太平洋
        for(int i = 0; i < n;i++){
            dfs(heights,0,i,pac);
        }
        for(int i = 0;i < m;i++){
            dfs(heights,i,0,pac);
        }
        //大西洋
        for(int i = 0;i < n;i++){
            dfs(heights,m-1,i,atl);
        }
        for(int i = 0;i < m;i++){
            dfs(heights,i,n-1,atl);
        }

        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(pac[i][j] && atl[i][j]){
                    List<Integer> tem = new ArrayList<>();
                    tem.add(i);
                    tem.add(j);
                    ret.add(tem);
                }
            }
        }
        return ret;
    }
    public void dfs(int[][] heights,int i,int j,boolean[][] vis){
        vis[i][j] = true;
        for(int k = 0;k < 4;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && heights[x][y] >= heights[i][j]){
                dfs(heights,x,y,vis);
            }
        }
    }

}

扫雷游戏

题目解析 :给了一个起始点击点,周围有雷就停止扩展,没有雷周围未被扩展的位置可以作为起始点扩展

思想:先统计雷的个数,有雷就更新结果停止扩展,没有就将其周围没有扩展位置作为起点开始扩展

此时这里周围是八个方向,因此可以使用两个dx和dy极坐标表示


java 复制代码
class Solution {
    int[] dx = { 0, 0, 1, -1, -1, 1, -1, 1 };
    int[] dy = { 1, -1, 0, 0, 1, -1, -1, 1 };
    int m, n;

    public char[][] updateBoard(char[][] board, int[] click) {
        m = board.length;
        n = board[0].length;
        int x = click[0];
        int y = click[1];

        if (board[x][y] == 'M') {
            board[x][y] = 'X';
            return board;
        }

        dfs(board, x, y);

        return board;
    }

    public void dfs(char[][] board, int i, int j) {
       //统计地雷的个数
        int count = 0;

        //上,下,左,右,和所有4个对角线
        for(int k = 0;k < 8;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            //统计周围地雷个数
            if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M'){
                count++;
            }
        }

        //周围没有雷的位置继续展开
        if(count == 0){
            board[i][j] = 'B';

            for(int k = 0;k < 8;k++){
                int x = i + dx[k];
                int y = j + dy[k];

                //统计周围地雷个数
                if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E'){
                    dfs(board,x,y);
                }
            }
        }else{
            board[i][j] = (char)(count+'0');
            return;
        }
    }
}

衣橱整理

题目解析 :找出有多少可以整理的格子,整理格子两坐标数位之和 <= cnt才可以整理,并且整理过程中选择向下 / 向右移动

思想:直接从(0,0)开始dfs扩展即可,判定是否满足数位要求,并且使用vis标记已经整理过的位置

java 复制代码
class Solution {
    int ret;
    int m, n,cnt;
    boolean[][] vis;

    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    public int wardrobeFinishing(int _m, int _n, int _cnt) {
        m = _m;
        n = _n;
        cnt = _cnt;
        vis = new boolean[m][n];
        dfs(0, 0);
       
        return ret;
    }

    public void dfs(int i, int j) {
        ret++;
        vis[i][j] = true;
        
        for(int k = 0;k < 4;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && vis[x][y] == false  && check(x,y) <= cnt){
               
                dfs(x,y);
            }
        }
    }

    public int check(int x, int y) {
        int tem = 0;
        while (x != 0) {
            tem += x % 10;
            x /= 10;
        }
        while (y != 0) {
            tem += y % 10;
            y /= 10;
        }
        return tem;
    }
}
相关推荐
上弦月-编程1 小时前
C语言指针从入门到实战
java·jvm·算法
WL_Aurora1 小时前
Python 算法基础篇之树和二叉树
python·算法
txzrxz1 小时前
关于前缀和
算法·动态规划·图论
杨连江2 小时前
载流子矩阵限域束缚实现常温常压超导的理论与结构设计
算法
做cv的小昊2 小时前
【TJU】研究生应用统计学课程笔记(6)——第二章 参数估计(2.4 区间估计)
人工智能·笔记·线性代数·算法·机器学习·数学建模·概率论
普贤莲花2 小时前
【2026年第18周---写于20260501】---舍得
程序人生·算法·leetcode
2zcode2 小时前
基于深度学习的口腔疾病图像识别系统(UI界面+改进算法+数据集+训练代码)
人工智能·深度学习·算法
Sarvartha2 小时前
N 个字符串最长公共子序列(LCS)求解问题
数据结构·算法
一切皆是因缘际会2 小时前
下一代 AI 架构:基于记忆演化与单向投影的安全智能系统
大数据·人工智能·深度学习·算法·安全·架构