【算法】【floodfill】洪水灌溉

2024-04-05 20:52
文章标签 算法 洪水 灌溉 floodfill

本文主要是介绍【算法】【floodfill】洪水灌溉,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1. 岛屿数量
  • 2. 岛屿最大面积
  • 3. 被围绕的区域
  • 4. 太平洋大西洋水流问题
  • 5. 扫雷游戏
  • 6. 机器人的运动范围

1. 岛屿数量

👉🔗题目链接

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

几个注意点:

  1. 二维深搜,巧妙使用全局方向矩阵
  2. 状态表记录,可以不改动原表
  3. 在搜索时注意 边界值 + 条件!!!
class Solution {
public:vector<vector<bool>> vis;int m, n;int numIslands(vector<vector<char>>& grid) {m = grid.size(), n = grid[0].size();vis = vector<vector<bool>>(m, vector<bool>(n));int count = 0;for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(grid[i][j] == '1' && !vis[i][j]){count++;dfs(grid, i, j);}}}return count;}int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};void dfs(const vector<vector<char>>& grid, int i, int j){vis[i][j] = true;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' && !vis[x][y]){dfs(grid, x, y);}}}
};

2. 岛屿最大面积

👉🔗题目链接

给定一个由 0 和 1 组成的非空二维数组 grid ,用来表示海洋岛屿地图。
一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

和上述代码雷同!仔细设计一下哪些做全局变量吧~


3. 被围绕的区域

👉🔗题目链接

给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充

和上述的题目相似,但有差别!
在边界上出现的 ‘O’ 不能计入,如果还使用之前的方法,在触碰边界条件的时候回退,代码逻辑编写起来是有困难的!怎么办呢?

正着写麻烦,就反着来吧。

先解决所有边界上的值,周围一圈的值,碰到一个 ‘O’ 就深搜一下,修改成 ‘+’。再把里面的都修改成 ‘X’ 不就解决啦!

在这里插入图片描述

class Solution {
public:int m, n;void solve(vector<vector<char>>& board) {m = board.size();n = board[0].size();// 1.将外面一圈的O相连的连通块,都处理了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);}// 2.还原:将O都改成X,将+都改成Ofor(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';}   }int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};// 把与进入位置相连的块都改成+void dfs(vector<vector<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);}}
};

4. 太平洋大西洋水流问题

👉🔗题目链接

手动翻译一下脑残的题目:给出的矩阵中,每个数字是高于海平面的高度。水可以从高处往低处流,也可以往相同高度流,矩阵边界的水都可以往海里流。按照他给出的两个海的位置,返回一系列[x, y]位置,要求这些位置上的水,既可以流向大西洋也可以流向太平洋。(图中橙色标记的格子的 index 就是满足条件的,也就是需要返回的)
在这里插入图片描述

解法1:

  • 暴力解法,对每一个格子进行判断,既能到左上,又能到右下则加入返回集合。
  • 逻辑比较好写,就是有很多重复路径,不太聪明(sos

解法2:

  • 正难则反
  • 从边界开始反推,哪些地方的水是可以流向太平洋 / 大西洋的!
  • 最后两边一汇总就是最后可以输出的结果。
class Solution {
public:int m, n;vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {m = heights.size();n = heights[0].size();vector<vector<bool>> pac(m, vector<bool>(n));vector<vector<bool>> ath(m, vector<bool>(n));vector<vector<int>> ret;// 1.填充两张状态表for(int i = 0; i < m; i++){// 太平洋:左if(!pac[i][0]) dfs(heights, i, 0, pac);// 大西洋:右if(!ath[i][n-1]) dfs(heights, i, n-1, ath);}for(int j = 0; j < n; j++){// 太平洋: 上if(!pac[0][j]) dfs(heights, 0, j, pac);// 大西洋: 下if(!ath[m-1][j]) dfs(heights, m-1, j, ath);}// 2.找出重合坐标for(int i = 0; i < m; i++)for(int j = 0; j < n; j++)if(pac[i][j] && ath[i][j])ret.push_back(vector<int>{i,j});return ret;}int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};void dfs(const vector<vector<int>>& heights, int i, int j, vector<vector<bool>>& status){status[i][j] = true;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 && heights[x][y] >= heights[i][j] && !status[x][y])dfs(heights, x, y, status);}}
};

5. 扫雷游戏

👉🔗题目链接

  • ‘M’ 代表一个 未挖出的 地雷,
  • ‘E’ 代表一个 未挖出的 空方块,
  • ‘B’ 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的 已挖出的 空白方块, 数字(‘1’ 到 ‘8’)表示有多少地雷与这块已挖出的 方块相邻, ‘X’ 则表示一个 已挖出的 地雷。 给你一个整数数组 click ,其中 click = [clickr, clickc] 表示在所有 未挖出的 方块(‘M’ 或者 ‘E’)中的下一个点击位置(clickr 是行下标,clickc 是列下标)。

根据以下规则,返回相应位置被点击后对应的盘面:

  • 如果一个地雷(‘M’)被挖出,游戏就结束了- 把它改为 ‘X’ 。
  • 如果一个 没有相邻地雷 的空方块(‘E’)被挖出,修改它为(‘B’),并且所有和其相邻的 未挖出 方块都应该被递归地揭露。
  • 如果一个 至少与一个地雷相邻 的空方块(‘E’)被挖出,修改它为数字(‘1’ 到 ‘8’ ),表示相邻地雷的数量。
  • 如果在此次点击中,若无更多方块可被揭露,则返回盘面。

👉🔗游戏链接

class Solution {
public:int m, n;int dx[8] = {0,0,1,-1,1,1,-1,-1};int dy[8] = {1,-1,0,0,1,-1,1,-1};vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {m = board.size();n = board[0].size();int i = click[0];int j = click[1];// 是地雷if(board[i][j] == 'M') {board[i][j] = 'X';return board;}// 不是地雷dfs(board, i, j);return board;}void dfs(vector<vector<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){board[i][j] = '0' + count;return;}// 没有地雷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);}}
};

能少走两次 count_and_modify_M 的写法:

class Solution {
public:int m, n;int dx[8] = {0,0,1,-1,1,1,-1,-1};int dy[8] = {1,-1,0,0,1,-1,1,-1};// 求 i,j 位置一周地雷的个数,如果有地雷,则修改boardint count_and_modify_M (vector<vector<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] = '0' + count;return count;}vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {m = board.size();n = board[0].size();int i = click[0];int j = click[1];// 是地雷if(board[i][j] == 'M') {board[i][j] = 'X';return board;}// 是已经挖开的if(board[i][j] == 'B' || (board[i][j] >= '0'+ 1 && board[i][j] <= '0'+ 8))return board;// 是挨着地雷的if(count_and_modify_M(board, i, j) != 0)return board;// 进入递归并判断dfs(board, i, j);return board;}void dfs(vector<vector<char>>& board, int i, int j){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' || board[x][y] == 'M') && count_and_modify_M(board, x, y) == 0)dfs(board, x, y);}}
};

6. 机器人的运动范围

👉🔗题目链接

地上有一个 rows 行和 cols 列的方格。坐标从 [0,0] 到 [rows-1,cols-1] 。一个机器人从坐标 [0,0] 的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 threshold 的格子。 例如,当 threshold 为 18 时,机器人能够进入方格 [35,37] ,因为 3+5+3+7 = 18。但是,它不能进入方格 [35,38] ,因为 3+5+3+8 = 19 。请问该机器人能够达到多少个格子?

拿到题目,别被数位之和唬住了。

机器人能走的路径是连续的,这里也就是从(0,0)开始,一次深搜的事儿,数位之和只是一个边界条件嘛!

#include <vector>
#include <iostream>
using namespace std;
class Solution 
{
public:int m, n, k, ret = 0;vector<vector<bool>> vis;int movingCount(int threshold, int rows, int cols) {m = rows, n = cols, k = threshold;vis = vector<vector<bool>>(m, vector<bool>(n));dfs(0, 0);return ret;   }int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};void dfs(int i, int j){     ret++;vis[i][j] = true;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 && !vis[x][y] && is_accessible(x, y))dfs(x, y);}}bool is_accessible(int x, int y){int sum = 0;while(x){sum += x % 10;x /= 10;}while(y){sum += y % 10;y /= 10;}if(sum <= k)return true;return false;}
};

🥰如果本文对你有些帮助,欢迎👉 点赞 收藏 关注,你的支持是对作者大大莫大的鼓励!!(✿◡‿◡) 若有差错恳请留言指正~~


这篇关于【算法】【floodfill】洪水灌溉的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/878125

相关文章

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯: