130. 被围绕的区域 Krains 2020-08-11 10:50:01 并查集DFS
时间:2022-07-23
本文章向大家介绍130. 被围绕的区域 Krains 2020-08-11 10:50:01 并查集DFS,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
# 题目链接
DFS
解题思路
从边缘的'O'出发,用dfs将所有与边缘相邻的'O'改成'A',未与边缘相邻的'O'将不会改变,然后遍历矩阵,将所有的'A'改成'O',所有的'O'改成'X'
错误思路
从里边的'O'出发,用dfs将所有相邻的'O'改成'X',如果搜索过程中碰到了边缘的'O',则回溯。这个思路错就错在回溯只能将一条到边缘'O'的路径还原,并不能还原其他走向“死胡同”的'O'。
class Solution {
int[][] d = new int[][]{{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int m;
int n;
public void solve(char[][] board) {
m = board.length;
if(m == 0)
return;
n = board[0].length;
// 从上下左右四个边缘出发
for(int i = 0; i < n; i++){
dfs(board, 0, i);
dfs(board, m-1, i);
}
for(int i = 0; i < m; i++){
dfs(board, i, 0);
dfs(board, i, n-1);
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(board[i][j] == 'A')
board[i][j] = 'O';
else if(board[i][j] == 'O')
board[i][j] = 'X';
}
}
}
private void dfs(char[][] board, int x, int y){
if(x < 0 || x >= m || y < 0 || y >= n || board[x][y] != 'O')
return ;
board[x][y] = 'A';
for(int i = 0; i < 4; i++)
dfs(board, x + d[i][0], y + d[i][1]);
}
}
BFS
与dfs思路相同,bfs的版本
class Solution {
int[][] d = new int[][]{{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int m;
int n;
public void solve(char[][] board) {
m = board.length;
if(m == 0)
return;
n = board[0].length;
Deque<int[]> queue = new LinkedList<>();
for(int i = 0; i < n; i++){
if(board[0][i] == 'O')
queue.add(new int[]{0, i});
if(board[m-1][i] == 'O')
queue.add(new int[]{m-1, i});
}
for(int i = 1; i < m-1; i++){
if(board[i][0] == 'O')
queue.add(new int[]{i, 0});
if(board[i][n-1] == 'O')
queue.add(new int[]{i, n-1});
}
while(!queue.isEmpty()){
int[] t = queue.remove();
board[t[0]][t[1]] = 'A';
for(int i = 0; i < 4; i++){
int x = t[0] + d[i][0];
int y = t[1] + d[i][1];
if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O'){
queue.add(new int[]{x, y});
}
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(board[i][j] == 'A')
board[i][j] = 'O';
else if(board[i][j] == 'O')
board[i][j] = 'X';
}
}
}
}
并查集
解题思路
- 将各个坐标映射到一维,范围在
[0, m*n-1]
,同时定义一个超级源点m*n,这个源点与所有边缘的'O'相连 - 对于在里边的'O'来说,将其与上下左右四个方向的'O'连接起来
- 最后在遍历一遍矩阵,将没有与src连接在一块的'O'置为'X'
class Solution {
// 定义并查集
class UnionFind{
int[] parents;
UnionFind(int size){
parents = new int[size];
for(int i = 0; i < size; i++)
parents[i] = i;
}
public int find(int x){
if(parents[x] == x)
return x;
return parents[x] = find(parents[x]);
}
public void union(int x, int y){
int px = find(x);
int py = find(y);
if(px == py)
return ;
parents[px] = py;
}
public boolean isConnect(int x, int y){
return find(x) == find(y);
}
}
int[][] d = new int[][]{{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int m;
int n;
public void solve(char[][] board) {
m = board.length;
if(m == 0)
return;
n = board[0].length;
int size = m * n + 1;
int src = m * n;
UnionFind u = new UnionFind(size);
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(board[i][j] == 'X')
continue;
// 将边缘的'O'与超级源点src相连接
if(i == 0 || i == m-1 || j == 0 || j == n-1)
u.union(src, i * n + j);
else{
// 将周围的'O'与(i, j)连接
for(int k = 0; k < 4; k++){
int x = i + d[k][0];
int y = j + d[k][1];
if(board[x][y] == 'O')
u.union(i * n + j , x * n + y);
}
}
}
}
for(int i = 1; i < m-1; i++){
for(int j = 1; j < n-1; j++){
if(board[i][j] == 'O' && !u.isConnect(src, i * n + j)){
board[i][j] = 'X';
}
}
}
}
}
- 从0学习MySQL系列(二)安装篇
- 从0学习MySQL系列(三)概念篇
- SQL Server基础SQL脚本之主外键约束
- SQL Server基础SQL脚本之Group By
- SQL Server基础SQL脚本之内外连接、交叉连接;函数、子查询
- MySQL 面试选择题15道(单选)
- SQL Server基础SQL脚本之分区表、分区方案
- SQL Server基础SQL脚本之创建架构、排序
- 枚举算法(Enumeration algorithm)实例一
- 剑指offer代码解析——面试题16反转单链表
- QMainWindow 和 QWidget 设置layout
- 安全工具Aircrack-ng的使用
- Windows Server 2008 R2 搭建微信小程序
- insert事务产生duplicate key error引发的死锁分析
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 控件设置阴影效果
- 解决VScode配置远程调试Linux程序的问题
- Android EasyBarrage实现轻量级弹幕效果
- android 获取本机其他app的版本信息的示例代码
- android相册选择图片的编码实现代码
- ClickHouse和他的朋友们(2)MySQL Protocol和Read调用栈
- Android图片三级缓存的原理及其实现
- Android TextView实现带链接文字事件监听的三种常用方式示例
- Android ViewDragHelper使用介绍
- Android语音声波控件 Android条形波控件
- Ubuntu下安装CUDA10.0以及问题
- Android ListView实现单选及多选等功能示例
- Recyclerview添加头布局和尾布局、item点击事件详解
- Android 中LayoutInflater.inflate()方法的介绍
- Android ListView实现简单列表功能