《并查集》130. 被围绕的区域《leetcode》

130. 被围绕的区域

难度中等422

给定一个二维的矩阵,包含 'X' 和 'O'字母 O)。

找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

示例:

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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

 

思路解析:

思路1.

首先正常的用并查集构建分支,然后遍历边界为“O”的点,用HashSet存储此点的根节点,再次遍历全图,如果为“O”点的根节点不在Hashset中,那么将“O”转变为“X”。

思路2:优化

定义一个节点 把所有边界的“O”节点的根节点设为它,然后正常用并查集建立分支,最后遍历全图,只有“O”节点的根节点不是它,就转变为“X”。

时间复杂度:定义find的最大路径长度为l,则时间复杂度为O(n*m*l)。

空间复杂度:O(n*m)。

思路1AC代码:

class Solution {
    
    Map<Integer,Integer>root=new HashMap<>();
    public int n,m;

    public boolean isOk(int x,int y,char[][] board)
    {
        if(x>=0&&x<n&&y>=0&&y<m&&board[x][y]=='O')
            return true;
        return false;
    }

    public int getIndex(int x,int y)
    {
        return x*m+y;
    }

    public int find(int x)
    {

        while(x!=root.get(x))
        {
            root.put(root.get(x),root.get(root.get(x)));
            x=root.get(x);//将x赋值为父亲节点的父亲节点。 从而实现路径压缩。
        }
        return x;
    }

    public void union(int x,int y)
    {
        int rootX=find(x);
        int rootY=find(y);
        if(rootX!=rootY)
            root.put(rootX,rootY);
        return ; 
    }

    public void solve(char[][] board) {
        n=board.length;
        if(n==0)
            return ;
        m=board[0].length;

        for(int i=0;i<n;i++)//初始化
            for(int j=0;j<m;j++)
                if(isOk(i,j,board))
                    root.put(getIndex(i,j),getIndex(i,j));
        
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(isOk(i,j,board))
                {
                    if(isOk(i-1,j,board))//只更新左上两个方向就ok
                        union(getIndex(i,j),getIndex(i-1,j));
                    if(isOk(i,j-1,board))
                        union(getIndex(i,j),getIndex(i,j-1));
                }

        Set<Integer>set=new HashSet<Integer>();
        for(int i=0; i<n;i++)//列边界
        {
            if(isOk(i,0,board))
                set.add(find(getIndex(i,0)));
            if(isOk(i,m-1,board))
                set.add(find(getIndex(i,m-1)));
        }

        for(int j=0; j<m;j++)//行边界
        {
            if(isOk(0,j,board))
                set.add(find(getIndex(0,j)));
            if(isOk(n-1,j,board))
                set.add(find(getIndex(n-1,j)));
        }

        for(int i=0;i<n;i++)//遍历
            for(int j=0;j<m;j++)
                if(isOk(i,j,board)&&!set.contains(find(getIndex(i,j))))
                    board[i][j]='X';

        return ;
    }
}

思路2AC代码:

class Solution {
    
    Map<Integer,Integer>root=new HashMap<>();
    public int n,m;
    public int dummyRoot=-1;

    public boolean isOk(int x,int y,char[][] board)
    {
        if(x>=0&&x<n&&y>=0&&y<m&&board[x][y]=='O')
            return true;
        return false;
    }

    public boolean isEdge(int x,int y)
    {
        return x==0||y==0||x==n-1||y==m-1? true:false;
    }
    public int getIndex(int x,int y)
    {
        return x*m+y;
    }

    public int find(int x)
    {
        while(x!=root.get(x))
            x=root.get(x);
        return x;
    }

    public void union(int x,int y)
    {
        int rootX=find(x);
        int rootY=find(y);
        if(rootX!=rootY)
            root.put(Math.max(rootX,rootY),Math.min(rootX,rootY));//为了使额外点成为根节点。
        return ; 
    }

    public void solve(char[][] board) {
        n=board.length;
        if(n==0)
            return ;
        m=board[0].length;
        root.put(dummyRoot,dummyRoot);//设置额外点
        for(int i=0;i<n;i++)//初始化
            for(int j=0;j<m;j++)
                if(isOk(i,j,board))
                {
                    if(isEdge(i,j))
                        root.put(getIndex(i,j),dummyRoot);//边界“O”点的根节点设置为额外点。
                    else
                        root.put(getIndex(i,j),getIndex(i,j));
                }

        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(isOk(i,j,board))
                {
                    if(isOk(i-1,j,board))
                        union(getIndex(i,j),getIndex(i-1,j));
                    if(isOk(i,j-1,board))
                        union(getIndex(i,j),getIndex(i,j-1));
                }
        
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(isOk(i,j,board)&&find(getIndex(i,j))!=dummyRoot)
                    board[i][j]='X';

        return ;
    }
}

再提一点:

一、并查集有两个点需要注意:

1.可以加路径压缩。

2.小树加到大树上。需要+HashMap size;

二、

就是set集合可以了解一下了,我找了一篇不错的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值