当前位置:首页 » 《资源分享》 » 正文

算法【Java】—— FloodFill 算法

25 人参与  2024年11月07日 18:43  分类 : 《资源分享》  评论

点击全文阅读


floodfill

floodfill 算法又被称为洪水灌溉算法,本质上就是一种暴力搜索算法。

下面我来带领大家感受一些这个算法在题目中的使用。

实战演练

图形渲染

https://leetcode.cn/problems/flood-fill
在这里插入图片描述


解析:
题意解读:当我们的起始位置的颜色与需要设置的目标颜色一致的时候,我们不用做任何的修改,也就是可以不进行搜索了。
如果起始位置和目标颜色不一致,我们需要把它周围和它一样的颜色的像素块改成目标颜色,所以我们在修个这个起始位置的像素块的时候,我们要先保存记录,方便后续搜索。

如何搜索???
我们要从起始位置开始向上下左右四个方向进行搜索,这里我们可以定义向量组,int[] dx = {0, 0, 1, -1};int[] dy = {1, -1, 0, 0}; 方便我们遍历四个方向进行深度搜索,下面的题目也是以深搜为例讲解。

然后开始关心其中一个像素块在做什么?这就是子问题,递归的函数体。
首先从这个位置看看四个方向有没有要修改的,如果有就进入它进行下一个递归。所以这里使用 for 循环,循环四次把四个方向遍历到,进行判断(下标不能越界还有这个方块是和起始位置的颜色是一致的)进入递归。

每次进入递归的时候,我们顺便把方块的数值进行修改即可。

class Solution {    int[] dx = {0, 0, 1, -1};    int[] dy = {1, -1, 0, 0};    int m, n, color, find;    public int[][] floodFill(int[][] image, int sr, int sc, int _color) {        m = image.length;        n = image[0].length;        color = _color;        if(image[sr][sc] != color) {            find = image[sr][sc];            dfs(image, sr, sc);        }         return image;    }    void dfs(int[][] image, int i, int j) {        image[i][j] = color;        for(int k = 0; k < 4; k++) {            int x = i + dx[k], y = j + dy[k];            if(x >= 0 && x < m && y >= 0 && y < n && image[x][y] == find) {                dfs(image, x, y);            }         }    }}

岛屿数量

https://leetcode.cn/problems/number-of-islands

在这里插入图片描述


解析:
首先岛屿只能由上下左右四个方向的陆地进行连接,所以我们可以先设置向量组,方便后续的遍历。
接着我们遍历所有的地区,当遇到陆地的时候,进行深搜,把和它相邻的陆地找到并都修改为 0,这样这一块岛屿就被销毁了,计数器也随机加 1,当所有的方块遍历完毕,岛屿数量也就出来了。

class Solution {    int[] dx = {0, 0, 1, -1};    int[] dy = {1, -1, 0, 0};    int m, n;    public int numIslands(char[][] grid) {        int count = 0;        m = grid.length;        n = grid[0].length;        for(int i = 0; i < m; i++) {            for(int j = 0; j < n; j++) {                if(grid[i][j] == '1') {                    dfs(grid, i, j);                    count++;                }            }        }        return count;    }    void dfs(char[][] grid, int i, int j) {        grid[i][j] = '0';        for(int k = 0; k < 4; k++) {            int x = i + dx[k], y = j + dy[k];            if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1') {                dfs(grid, x, y);            }        }    }}

岛屿的最大面积

https://leetcode.cn/problems/max-area-of-island

在这里插入图片描述

解析:
我们找到所有的岛屿,并记录好该岛屿的面积,然后进行比较就可以得到最大的面积值。

class Solution {    int[] dx = {0, 0, 1, -1};    int[] dy = {1, -1, 0, 0};    int m, n, sum, count;    public int maxAreaOfIsland(int[][] grid) {        m = grid.length;        n = grid[0].length;        for(int i = 0; i < m; i++) {            for(int j = 0; j < n; j++) {                if(grid[i][j] == 1) {                    dfs(grid, i, j);                    sum = Math.max(sum, count);                    count = 0;                }            }        }        return sum;    }    void dfs(int[][] grid, int i, int j) {        grid[i][j] = 0;        count++;        for(int k = 0; k < 4; k++) {            int x = i + dx[k], y = j + dy[k];            if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) {                dfs(grid, x, y);            }        }    }}

被围绕的区域

https://leetcode.cn/problems/surrounded-regions

在这里插入图片描述


解析:
题意分析:首先一个区域的定义是这个区域是由上下左右这四个方向的 O 方块组成的,所以我们要想遍历某个区域,就得把这四个方向都搜索一遍,这里我们就可以使用向量组。

被围绕的区域是指这个区域的上下左右四个方向都被 X 给包围了,如果这个区域是被包围的,那就要把这个区域所有的 O 修改为 X

如何搜索???
如果你想暴力所有的方块,也就是把所有的区域都找到,然后从中找到被包围的区域,你会发现做起来很麻烦,因为你的区域需要标记要么原地标记要么再开一个数组来作为标记数组,之后如果发现这个区域没有被包围,那就需要回溯的时候还原现场,特别麻烦

既然正着来做,我们就反着做,这就是正难则反,也是逆向思维的体现。

因为没有被包围的区域一定存在每个或者某些方块是位于数组的边缘地带,所以我们可以把数组的边缘给遍历一遍,找到 O 方块,然后对其进行深搜,把这个没有被包围的区域找到并标记起来,这里我直接在原数组进行标记,把没有被包围的区域用 . 给标记起来。

等到边缘地区都被搜索完成之后,我们对整个数组进行一次遍历,把所有 O 修改为 X,所有 . 还原为 O

这样就完成了任务。

class Solution {    int[] dx = {0, 0, 1, -1};    int[] dy = {1, -1, 0, 0};    int m, n;    public void solve(char[][] board) {        m = board.length;        n = board[0].length;        for(int i = 0; i < m; i++) {            if(board[i][0] == 'O') {                dfs(board, i, 0);            }            if(board[i][n-1] == 'O') {                dfs(board, i, n-1);            }        }        for(int j = 0; j < n; j++) {            if(board[0][j] == 'O') {                dfs(board, 0, j);            }            if(board[m - 1][j] == 'O') {                dfs(board, m-1, j);            }        }        for(int i = 0; i < m; i++) {            for(int j = 0; j < n; j++) {                if(board[i][j] == '.') {                    board[i][j] = 'O';                } else if(board[i][j] == 'O') {                    board[i][j] = 'X';                }            }        }    }    void dfs(char[][] board, int i, int j) {        board[i][j] = '.';        for(int k = 0; k < 4; k++) {            int x = i + dx[k], y = j + dy[k];            if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O') {                dfs(board, x, y);            }        }    }}

扫雷游戏

https://leetcode.cn/problems/minesweeper

在这里插入图片描述


解析:
题意分析:首先如果一开始就踩到地雷 ‘M’,那么就把这个位置修改为 ‘X’,并且直接返回

如果一开始没有踩到地雷,那我们就进行深搜,首先扫雷游戏是需要搜索一个方块周围上下左右以及对角线一共八个方向的方块,因此这个我们定义的向量组要能够覆盖到这八个方向。
当这八个方向存在地雷的时候,那么这个位置需要显示出周围一共由多少颗地雷,接着就不用继续递归展开了。
如果正好这八个方向都没有地雷,那么我们需要将这个位置修改为 ‘B’,接着向这八个方向进行深搜展开。

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';        } else {            dfs(board, x, y);        }        return board;    }    void dfs(char[][] board, int i, int j) {        int count = 0;//标记此时周围的地雷数量        for(int k = 0; k < 8; k++) {            int x = i + dx[k], y = j + dy[k];            if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M') {                count++;            }        }        if(count != 0) {            board[i][j] = (char)('0' + count);        } else {            board[i][j] = 'B';            for(int k = 0; k < 8; k++) {                int x = i + dx[k], y = j + dy[k];                if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E') {                    dfs(board, x, y);                }            }        }    }}

衣橱整理 (机器人的运动范围)

https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof

在这里插入图片描述

题目解析:这里要注意我们要求的是家具整理师的运动范围,当遇到不用整理的格子的时候,我们不能进入这个方块内,当遇到可以整理的方格的时候我们可以进入并且下一次的运动方向是向下或者向右,我们需要求的是运动范围的大小,相信看到这里大家已经知道怎么做了。
在这里插入图片描述

首先我们先定义向量组,然后创建一个方法 digit(int x) 来统计 x 的各位数字之和,再创建一个标记数组标记该位置是否来过。
接下来就是从 (0,0)这个位置开始进行深搜。


class Solution {    int[] dx = {0, 1};    int[] dy = {1, 0};    int m, n, count;    boolean[][] check;    public int wardrobeFinishing(int _m, int _n, int cnt) {        m = _m;        n = _n;        check = new boolean[m][n];        dfs(0, 0, cnt);        return count;    }    void dfs(int i, int j, int cnt) {        count++;        check[i][j] = true;        for(int k = 0; k < 2; k++) {            int x = i + dx[k], y = j + dy[k];            if(x >= 0 && x < m && y >= 0 && y < n && !check[x][y] &&            digit(x) + digit(y) <= cnt) {                dfs(x, y, cnt);            }        }    }    int digit(int x) {        int sum = 0;        while(x != 0) {            sum += (x % 10);            x /= 10;        }        return sum;    }}

点击全文阅读


本文链接:http://zhangshiyu.com/post/183836.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

最新文章

  • 祖母寿宴,侯府冒牌嫡女被打脸了(沈屿安秦秀婉)阅读 -
  • 《雕花锦年,昭都旧梦》(裴辞鹤昭都)完结版小说全文免费阅读_最新热门小说《雕花锦年,昭都旧梦》(裴辞鹤昭都) -
  • 郊区41号(许洛竹王云云)完整版免费阅读_最新全本小说郊区41号(许洛竹王云云) -
  • 负我情深几许(白诗茵陆司宴)完结版小说阅读_最热门小说排行榜负我情深几许白诗茵陆司宴 -
  • 九胞胎孕妇赖上我萱萱蓉蓉免费阅读全文_免费小说在线看九胞胎孕妇赖上我萱萱蓉蓉 -
  • 为保白月光,侯爷拿我抵了债(谢景安花田)小说完结版_完结版小说全文免费阅读为保白月光,侯爷拿我抵了债谢景安花田 -
  • 陆望程映川上官硕《我的阿爹是带攻略系统的替身》最新章节阅读_(我的阿爹是带攻略系统的替身)全章节免费在线阅读陆望程映川上官硕
  • 郑雅琴魏旭明免费阅读_郑雅琴魏旭明小说全文阅读笔趣阁
  • 头条热门小说《乔书意贺宴临(乔书意贺宴临)》乔书意贺宴临(全集完整小说大结局)全文阅读笔趣阁
  • 完结好看小说跨年夜,老婆初恋送儿子故意出车祸_沈月柔林瀚枫完结的小说免费阅读推荐
  • 热推《郑雅琴魏旭明》郑雅琴魏旭明~小说全文阅读~完本【已完结】笔趣阁
  • 《你的遗憾与我无关》宋怀川冯洛洛无弹窗小说免费阅读_免费小说大全《你的遗憾与我无关》宋怀川冯洛洛 -

    关于我们 | 我要投稿 | 免责申明

    Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1