【四十一】【算法分析与设计】floodfill(2),130. 被围绕的区域,417. 太平洋大西洋水流问题

news2024/11/27 0:16:10

 

目录

130. 被围绕的区域

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

结尾






130. 被围绕的区域

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

示例 1:

 
 

输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]] 输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]] 解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

示例 2:

输入:board = [["X"]] 输出:[["X"]]

提示:

  • m == board.length

  • n == board[i].length

  • 1 <= m, n <= 200

  • board[i][j]'X''O'

问题的关键在于划分集合,一个集合是与边界相连的O区域,另一个集合是不与边界相连的O区域。

因此可以考虑所有与边界相连的O区域进行集合划分。

利用visit进行集合划分。

 
class Solution {
public:
    vector<vector<bool>> visit;
    int row, col;
    void solve(vector<vector<char>>& board) {
        row = board.size(), col = board[0].size();
        visit = vector<vector<bool>>(row, vector<bool>(col));

        for (int i = 0; i < row; i++) {
            if (board[i][0] == 'O')
                dfs(board, i, 0);
            if (board[i][col - 1] == 'O')
                dfs(board, i, col - 1);
        }
        for (int j = 0; j < col; j++) {
            if (board[0][j] == 'O')
                dfs(board, 0, j);
            if (board[row - 1][j] == 'O')
                dfs(board, row - 1, j);
        }

        for (int i = 0; i < row; i++)
            for (int j = 0; j < col; j++) {
                if (!visit[i][j] && board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
    }
    int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
    void dfs(vector<vector<char>>& board, int i, int j) {
        // visit
        // 当前
        visit[i][j] = true;
        // 下一层
        for (int k = 0; k < 4; k++) {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < row && y >= 0 && y < col && !visit[x][y] &&
                board[x][y] == 'O')
                dfs(board, x, y);
        }
    }
};

在一个二维的棋盘上,棋盘的每个位置要么是 'X' 要么是 'O'。规则是,只有在边缘上或者与边缘上的 'O' 直接或间接相连的 'O' 才不会被 'X' 替换。这个算法的目的是将所有不满足上述条件的 'O' 替换成 'X'。

class Solution {

public:

vector<vector<bool>> visit; // 用于记录棋盘上每个位置是否被访问过

int row, col; // 分别存储棋盘的行数和列数 // 主函数,用于处理棋盘

void solve(vector<vector<char>>& board) {

row = board.size(), col = board[0].size(); // 初始化行和列的大小

visit = vector<vector<bool>>(row, vector<bool>(col)); // 初始化访问标记数组

// 遍历棋盘的四个边缘,对于边缘上的每个 'O',执行深度优先搜索

for (int i = 0; i < row; i++) {

if (board[i][0] == 'O')

dfs(board, i, 0);

if (board[i][col - 1] == 'O')

dfs(board, i, col - 1);

}

for (int j = 0; j < col; j++) {

if (board[0][j] == 'O')

dfs(board, 0, j);

if (board[row - 1][j] == 'O')

dfs(board, row - 1, j);

} // 遍历整个棋盘,将所有未被访问过的 'O' 替换为 'X'

for (int i = 0; i < row; i++)

for (int j = 0; j < col; j++) {

if (!visit[i][j] && board[i][j] == 'O') {

board[i][j] = 'X';

}

}

} int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1}; // 方向数组,用于表示上下左右四个方向

// 深度优先搜索函数

void dfs(vector<vector<char>>& board, int i, int j) {

visit[i][j] = true; // 标记当前位置已访问

// 遍历当前位置的四个方向

for (int k = 0; k < 4; k++) {

int x = i + dx[k], y = j + dy[k];

// 如果下一个位置在棋盘内,未被访问过,且为 'O',则对其进行深度优先搜索

if (x >= 0 && x < row && y >= 0 && y < col && !visit[x][y] &&

board[x][y] == 'O')

dfs(board, x, y);

}

}

};

这段代码的关键在于,通过从边缘的 'O' 开始的深度优先搜索(DFS),我们可以找到所有与边缘上的 'O' 直接或间接相连的 'O',并通过访问数组标记它们。之后,遍历整个棋盘,将所有未被标记为已访问的 'O' 替换为 'X',从而达到题目的要求。

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

有一个 m × n 的矩形岛屿,与 太平洋大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。

这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heightsheights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度

岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。

返回网格坐标 result2D 列表 ,其中 result[i] = [r(i), c(i)] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋

示例 1:

输入: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]] 输出: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]

示例 2:

输入: heights = [[2,1],[1,2]] 输出: [[0,0],[0,1],[1,0],[1,1]]

提示:

  • m == heights.length

  • n == heights[r].length

  • 1 <= m, n <= 200

  • 0 <= heights[r][c] <= 10(5)

 
class Solution {
public:
    int row, col;
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& h) {
        row = h.size(), col = h[0].size();

        vector<vector<bool>> visit_pac(row, vector<bool>(col)),
            visit_atl(row, vector<bool>(col));

        for (int i = 0; i < row; i++) {
            dfs(h, i, 0, visit_pac);
            dfs(h, i, col - 1, visit_atl);
        }
        for (int j = 0; j < col; j++) {
            dfs(h, 0, j, visit_pac);
            dfs(h, row - 1, j, visit_atl);
        }

        vector<vector<int>> ret;

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (visit_atl[i][j] && visit_pac[i][j]) {
                    ret.push_back({i, j});
                }
            }
        }

        return ret;
    }

    int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
    void dfs(const vector<vector<int>>& h, int i, int j,
             vector<vector<bool>>& visit) {
        // visit
        // 当前
        visit[i][j] = true;
        // 下一层
        for (int k = 0; k < 4; k++) {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < row && y >= 0 && y < col && !visit[x][y] &&
                h[x][y] >= h[i][j]) {
                dfs(h, x, y, visit);
            }
        }
    }
};

这段代码解决的是“太平洋大西洋水流问题”。这个问题要求找出所有同时能流向太平洋和大西洋的单元格。太平洋位于矩阵的左边界和上边界,大西洋位于矩阵的右边界和下边界。水流只能从高到低或在相同高度上流动。给定的矩阵 h 中,每个单元格的值代表该地的高度。

int row, col; // 存储矩阵的行数和列数 // 主函数,返回能流向两大洋的所有单元格

vector<vector<int>> pacificAtlantic(vector<vector<int>>& h) {

row = h.size(), col = h[0].size(); // 初始化行数和列数 // 为太平洋和大西洋分别创建访问矩阵,用于标记是否可达

vector<vector<bool>> visit_pac(row, vector<bool>(col)),

visit_atl(row, vector<bool>(col)); // 从每个大洋的边缘开始,利用DFS标记可达的单元格

for (int i = 0; i < row; i++) {

dfs(h, i, 0, visit_pac); // 从太平洋左边缘开始

dfs(h, i, col - 1, visit_atl); // 从大西洋右边缘开始

}

for (int j = 0; j < col; j++) {

dfs(h, 0, j, visit_pac); // 从太平洋上边缘开始

dfs(h, row - 1, j, visit_atl); // 从大西洋下边缘开始

} vector<vector<int>> ret; // 用于存储结果的矩阵

// 遍历矩阵,找出同时被两个大洋访问过的单元格

for (int i = 0; i < row; i++) {

for (int j = 0; j < col; j++) {

if (visit_atl[i][j] && visit_pac[i][j]) {

ret.push_back({i, j}); // 同时可达两大洋的单元格

}

}

}

return ret; // 返回结果

}

int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1}; // 方向数组,用于在DFS中向四个方向探索 // DFS函数,用于从特定单元格开始,探索所有可达的单元格

void dfs(const vector<vector<int>>& h, int i, int j,

vector<vector<bool>>& visit) {

visit[i][j] = true; // 标记当前单元格为已访问

// 遍历四个方向

for (int k = 0; k < 4; k++) {

int x = i + dx[k], y = j + dy[k];

// 检查下一个单元格是否在矩阵内,未被访问,且高度不低于当前单元格

if (x >= 0 && x < row && y >= 0 && y < col && !visit[x][y] &&

h[x][y] >= h[i][j]) {

dfs(h, x, y, visit); // 对满足条件的单元格进行DFS

}

}

}

};

代码的核心思想是从两个大洋的边缘开始,反向查找可以流入大洋的单元格。通过DFS,我们可以找到所有从边缘到达当前单元格的路径,并将路径上的单元格标记为可达。最后,检查哪些单元格被两个大洋的访问数组同时标记为可达,这些单元格就是最终的答案,表示这些位置的水既可以流向太平洋,也可以流向大西洋。

初始化行列值和访问数组:通过 h.size()h[0].size() 获取矩阵的行数和列数,并为太平洋与大西洋分别创建一个访问数组(visit_pacvisit_atl),用布尔值表示每个单元格是否可以从对应的大洋流入。

从每个大洋的边缘开始深度优先搜索:对于矩阵的四个边缘(上边缘和左边缘为太平洋的边缘,下边缘和右边缘为大西洋的边缘),使用深度优先搜索标记所有从这些边缘可达的单元格。对于太平洋,从左边缘和上边缘的每个单元格开始搜索;对于大西洋,从右边缘和下边缘的每个单元格开始搜索。

合并结果:遍历整个矩阵,检查每个单元格是否同时在 visit_pacvisit_atl 中被标记为 true,如果是,表示这个位置的水既可以流向太平洋也可以流向大西洋,将其加入到结果列表中。

返回结果:将所有满足条件的单元格的坐标(行号和列号)作为结果返回。

代码中的 dfs 函数是解决问题的关键,它遵循以下规则:

从当前单元格出发,尝试向四个方向(上、下、左、右)移动。

移动的条件是目标单元格在矩阵内,未被当前大洋的访问数组访问过,且其高度不小于当前单元格的高度(表示水可以从当前单元格流向目标单元格)。

递归地对满足条件的目标单元格执行深度优先搜索,直到不再有满足条件的单元格为止。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

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

相关文章

长基线大高差RTK定位效果分析

为了评估基于GNSS参考站网的实时高精度滑坡监测算法效果&#xff0c;如图2所示&#xff0c;本文共收集了中国西北2019年年积日第271&#xff5e;277共7天的4个CORS站数据&#xff0c;分别为LZLC、BYBY、LXDX、LXJS&#xff0c; 2个黑方台滑坡监测站数据HF01和HF06&#xff0c;其…

算法:多重背包问题dp

文章目录 一、多重背包问题特点1.1、多重背包问题的特征1.2、解决多重背包问题的基本方法典型例题&#xff1a;AcWing——多重背包问题I 1.3、二进制优化1.3.1、二进制优化的思想1.3.2、多重背包问题的二进制优化 一、多重背包问题特点 多重背包问题是背包问题的又一变种&…

大厂设计师倾心推荐的在线作图免费网站

在当今数字时代&#xff0c;绘画已经成为各行各业的必备技能。无论你是设计师、学生、创作者还是业余爱好者&#xff0c;免费的在线绘图软件都是发挥创造力和表达想法的理想选择。本文将介绍七款强大免费的在线绘图软件&#xff0c;让你轻松实现自己的创作梦想。你可以在不安装…

功能测试_验证qq账号的合法性

案例&#xff1a;验证qq账号的合法性&#xff08;要求&#xff1a;6-10位的自然数&#xff09; 使用等价类设计用例案例&#xff1a; 步骤&#xff1a; 1:明确需求&#xff1a;qq账号的合法性 2:划分等价类&#xff1a;有效等价类、有效取值、无效等价类、无效取值 3&…

docker搭建EFK

目录 elasticsearch1.创建网络2.拉取镜像3.创建容器如果出现启动失败&#xff0c;提示目录挂载失败&#xff0c;可以考虑如下措施 开放防火墙端口4.验证安装成功重置es密码关闭https连接创建kibana用户创建新账户给账户授权 kibana1.创建容器2.验证安装成功3.es为kibana创建用户…

LeetCode-冗余连接(并查集)

每日一题&#xff0c;今天又刷到一道使用并查集来解决的问题&#xff0c;再次加深了一遍自己对并查集的印象和使用。 题目要求 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1&#xff5e;n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1…

Windows11下Docker使用记录(一)

Docker使用记录&#xff08;一&#xff09; 简单介绍Docker安装Docker 常用命令Docker 可视化Docker 使用GPU可视化rviz、gazebo 在进行ROS项目开发时&#xff0c;如果只有一台Windows电脑&#xff0c;我们可以考虑使用WSL或Docker来搭建ROS环境。在尝试了两种方式后&#xff0…

【静态分析】静态分析笔记01 - Introduction

参考&#xff1a; BV1zE411s77Z [南京大学]-[软件分析]课程学习笔记(一)-introduction_南京大学软件分析笔记-CSDN博客 ------------------------------------------------------------------------------------------------------ 1. program language and static analysis…

Python实现滑块验证码识别,最简单的一种,没有任何加密

网址链接&#xff1a;衣丰 & 2010-聚衣网(juyi5.cn) - 常熟市聚衣网&#xff0c;聚衣网女装&#xff0c;江苏省女装批发&#xff0c;苏州市女装批发&#xff0c;常熟市女装批发&#xff0c;网销女装一件代发&#xff0c;全国最低价 平时采集数据&#xff0c;频率过快&…

ai伪原创文案,快速生成文案的方法!

在当今数字化时代&#xff0c;文案写作成为广告、营销等领域中不可或缺的一环。然而&#xff0c;随着互联网的发展&#xff0c;市场上的竞争愈发激烈&#xff0c;传统的文案写作方式已经无法满足大家的需求。ai伪原创文案的出现&#xff0c;便成为一种快速的写作文案的方法。本…

PowerJob 分布式任务调度简介

目录 适用场景 设计目标 PowerJob 功能全景 任务调度 工作流 分布式计算 动态容器 什么是动态容器? 使用场景 可维护性和灵活性的完美结合 实时日志&在线运维 PowerJob 系统组件 PowerJob 应用场景 PowerJob 的优势 PowerJob&#xff08;原OhMyScheduler&…

中国500米分辨率年最大EVI数据集

增强型植被指数&#xff08;EVI&#xff09;是在归一化植被指数&#xff08;NDVI&#xff09;改善出来的&#xff0c;根据大气校正所包含的影像因子大气分子、气溶胶、薄云、水汽和臭氧等因素进行全面的大气校正&#xff0c;EVI大气校正分三步&#xff0c;第一步是去云处理。第…

基于SpringBoot+Vue网上医院预约挂号系统+jsp(源码+部署说明+演示视频+源码介绍+lw)

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

python使用uiautomator2操作雷电模拟器9

之前写过一篇文章 python使用uiautomator2操作雷电模拟器_uiautomator2 雷电模拟器-CSDN博客 上面这篇文章用的是雷电模拟器4&#xff0c;雷电模拟器4.0.78&#xff0c;android版本7.1.2。 今天有空&#xff0c;再使用雷电模拟器9&#xff0c;android版本9来测试一下 uiauto…

绝地求生29.1版本更新后进不去 绝地求生更新后进不去游戏怎么办

绝地求生游戏共有两种主要模式&#xff1a;第一人称模式和第三人称模式。在这两种模式下玩家可以分别进行单排&#xff0c;双排&#xff0c;四人组队或单人匹配四人团队模式。在进入游戏的时候&#xff0c;玩家可以在面板选择第一人称以及第三人称。在双排或四排等组队多人游戏…

【学习】软件测试需求分析要从哪些方面入手

软件测试需求分析是软件测试过程中非常重要的一个环节&#xff0c;它是为了明确软件测试的目标、范围、资源和时间等要素&#xff0c;以确保软件测试的有效性和全面性。本文将从以下几个方面对软件测试需求分析进行详细的阐述&#xff1a; 一、软件测试目标 软件测试目标是指…

CSS文本单行溢出和多行溢出样式

一、单行溢出 1.代码 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>demo</title><style>#div2{overflow: hidden;white-space: nowrap;/*强制不换行*/text-overflow:ellipsis;/*超出的部分用省略号代替*…

gitee和idea集成

1 集成插件 2 配置账号密码 3 直接将项目传到仓库 4直接从gitee下载项目

【Linux】有关时间的命令(date、timedatectl)

专栏文章索引&#xff1a;Linux 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、data命令 1.介绍 2.常用参数 3.常用选项 二、timedatectl命令 1.介绍 2.常用子命令 一、data命令 1.介绍 date命令用于显示或设置系统的时间与日期&#xff0c;语法格式为&a…

axios取消请求,解决接口返回顺序错乱问题

下面的方案适用于系统中的某个请求的取消&#xff0c;项目的请求使用 axios 封装 使用场景&#xff1a;当页面有多个 tab&#xff0c;例如年、月、日的列表数据&#xff0c;当点击切换的时候要获取对应的数据&#xff0c;此时如果快速点击在tab直接反复横跳会出现下面的问题&am…