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';
}
}
}
}
}
- ASP.NET Web API: 宿主(Hosting)
- 在 Windows Phone上使用QQConnect OAuth2
- WordPress 开发之使用WordPress 3.8+后台图标(dashicons)
- 基础(二)
- Ionic:高级的 HTML5 移动APP(Web App)开发框架
- 为WordPress 评论框添加HTML5 表单验证
- Sass 基础(一)
- 送上段模拟圣诞节下雪的javascript 代码
- 互联网:解开大脑之迷
- NEC 框架规范 template media
- NEC 框架规范 animation
- NEC 框架规范 css function
- NEC 框架规范 css reset
- NEC 工程师规范
- 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 数组属性和方法
- 总结java创建文件夹的4种方法及其优缺点-JAVA IO基础总结第三篇
- 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇
- 总结java中文件拷贝剪切的5种方式-JAVA IO基础总结第五篇
- 总结java中删除文件或文件夹的7种方法-JAVA IO基础总结第四篇
- 总结java中创建并写文件的五种方式-JAVA IO基础总结第一篇
- 8成以上的java线程状态图都画错了,看看这个-图解java并发第二篇
- 特殊数据格式处理-JSON框架Jackson精解第2篇
- 序列化与反序列化核心用法-JSON框架Jackson精解第一篇
- 属性序列化自定义排序与字母表排序-JSON框架Jackson精解第3篇
- 【我在拉勾训练营学技术】mysql 索引面试再也不怕啦
- 智能合约中常见的漏洞总结复现#技术创作101训练营#
- JS根据列表排列对象数组
- git提取两次提交或者版本的差异文件并打包成zip压缩包
- 博客通用版Live2d伊斯特瓦尔发布
- 一个小需求,自动重启k8s集群中日志不刷新的POD