ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Leetcode 130. 被围绕的区域(中等)DFS||并查集

2022-02-22 18:02:28  阅读:238  来源: 互联网

标签:dummy parent int 查集 DFS 130 board rootq size


130. 被围绕的区域(中等)

题目:

给你一个 M×N 的二维矩阵,其中包含字符 X 和 O,让你找到矩阵中四面被 X 围住的 O,并且把它们替换成 X

注意哦,必须是四面被围的 O 才能被换成 X,也就是说边角上的 O 一定不会被围,进一步,与边角上的 O 相连的 O 也不会被 X 围四面,也不会被替换。

 

思路1:

DFS

先遍历四条边,找出O,并对O节点进行深度遍历,将相邻的O节点都设为#

然后遍历所有节点,将O设为X,将#设为O

 

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        int m=board.size();
        int n=board[0].size();
        for(int i=0;i<m;++i){
            if(board[i][0]=='O'){
                traverse(board,i,0);
            }
            if(board[i][n-1]=='O'){
                traverse(board,i,n-1);
            }
        }
        for(int j=0;j<n;++j){
            if(board[0][j]=='O'){
                traverse(board,0,j);
            }
            if(board[m-1][j]=='O'){
                traverse(board,m-1,j);
            }
        }
        for(int i=0;i<m;++i){
            for(int j=0;j<n;++j){
                if(board[i][j]=='O'){
                    board[i][j]='X';
                }
                if(board[i][j]=='#'){
                    board[i][j]='O';
                }
            }
        }
    }
    void traverse(vector<vector<char>>& board, int m,int n){
        board[m][n]='#';
        for(int i=0;i<4;++i){
            int v=m+d[i][0];
            int w=n+d[i][1];
            if(v>=0&&v<board.size()&&w>=0&&w<board[0].size()){
                if(board[v][w]=='O'){
                    traverse(board,v,w);
                }
            }
        }
    }
    int d[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
};

 

思路2:

并查集

你可以把那些不需要被替换的O看成一个拥有独门绝技的门派,它们有一个共同祖师爷叫dummy,这些Odummy互相连通,而那些需要被替换的Odummy不连通

首先要解决的是,根据我们的实现,Union-Find 底层用的是一维数组,构造函数需要传入这个数组的大小,而题目给的是一个二维棋盘。

这个很简单,二维坐标(x,y)可以转换成x * n + y这个数(m是棋盘的行数,n是棋盘的列数)。敲黑板,这是将二维坐标映射到一维的常用技巧

其次,我们之前描述的「祖师爷」是虚构的,需要给他老人家留个位置。索引[0.. m*n-1]都是棋盘内坐标的一维映射,那就让这个虚拟的dummy节点占据索引m*n好了。

class UF{
public:
UF(int n){
    count=n;
    for(int i=0;i<n;++i){
        parent.push_back(i);
        size.push_back(1);
    }
    
}
//p和q连通
void Union(int p,int q){
    int rootp=find(p);
    int rootq=find(q);
    if(rootq==rootp)
        return;
    //小树接到大树下边,比较平均
    if(size[rootp]>size[rootq]){
        size[rootq]+=size[rootp];
        parent[rootp]=rootq;
    }else{
        size[rootp]+=size[rootq];
        parent[rootq]=rootp;
    }
    count--;
}
/* 返回节点 x 的根节点 */
int find(int x){
    while(x!=parent[x]){
        // 进行路径压缩
        parent[x]=parent[parent[x]];
        x=parent[x];
    }
    return x;
}
/* 判断 p 和 q 是否互相连通 */
bool connected(int p,int q){
    int rootp=find(p);
    int rootq=find(q);
    // 处于同一棵树上的节点,相互连通
    return rootp==rootq;
}
//记录连通分量个数
int count;
//存储若干棵树
vector<int> parent;
//记录树的重量
vector<int> size;
};
class Solution {
public:
    void solve(vector<vector<char>>& board) {
        int m=board.size();
        int n=board[0].size();
        // 给 dummy 留一个额外位置
        UF uf(m*n+1);
        int dummy=m*n;
        // 将首列和末列的 O 与 dummy 连通
        for(int i=0;i<m;++i){
            if(board[i][0]=='O'){
                uf.Union(i*n,dummy);
            }
            if(board[i][n-1]=='O'){
                uf.Union(i*n+n-1,dummy);
            }
        }
        // 将首行和末行的 O 与 dummy 连通
        for(int j=0;j<n;++j){
            if(board[0][j]=='O'){
                uf.Union(j,dummy);
            }
            if(board[m-1][j]=='O'){
                uf.Union((m-1)*n+j,dummy);
            }
        }
        for(int i=1;i<m-1;++i){
            for(int j=1;j<n-1;++j){
                if(board[i][j]=='O'){
                    // 将此 O 与上下左右的 O 连通
                    for(int k=0;k<4;++k){
                        int v=i+d[k][0];
                        int w=j+d[k][1];
                        if(board[v][w]=='O'){
                            uf.Union(v*n+w,i*n+j);
                        }
                    }
                }
            }
        }
        // 所有不和 dummy 连通的 O,都要被替换
        for(int i=0;i<m;++i){
            for(int j=0;j<n;++j){
                if(board[i][j]=='O'){
                    if(!uf.connected(i*n+j,dummy)){
                        board[i][j]='X';
                    }
                }
            }
        }
    }
    // 方向数组 d 是上下左右搜索的常用手法
    int d[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
};

 

标签:dummy,parent,int,查集,DFS,130,board,rootq,size
来源: https://www.cnblogs.com/zl1991/p/15924271.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有