【并查集】B002_被环绕的区域(并查集 | DFS | BFS)

一、题目描述

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.

Example:

X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X
Explanation:

Surrounded regions shouldn’t be on the border, 
which means that any 'O' on the border of the board are not flipped to 'X'. 
Any 'O' that is not on the border and it is not connected to an 'O' on the border will be flipped to 'X'. 
Two cells are connected if they are adjacent cells connected horizontally or vertically.

二、题解

(1) 并查集

这题跟 岛屿的数量 不同的是这题不需要求连通分量的个数 c o u n t count ,所以下面的代码删掉了 c o u n t count

核心思想列举如下:

  • 处理网格 g r i d grid 边界上的 O 'O' 结点。这里的方法是:遇到 O O 就执行并查集合并操作,这样所有的 O O 就会被分成两类 —>
    • 和边界上的 O O 在一个连通区域内的。
    • 不和边界上的 O O 在一个连通区域内的。如何区别他们呢?
  • 我们使用一个边界结点 s t a t i c V a l staticVal ,其值可为边界上的任意坐标,当遇到 O O ,并且它是边界上的 O O 时,我们将这类 O O s t a t i c V a l staticVal 所在的树进行 u n i o n union ;非边界上的 O O ,我们按题目要求,将其与上下左右的 O O 进行 u n i o n union
  • 最后我们再次按照网格大小进行遍历网格坐标,查找不与 s t a t i c V a l staticVal 相连的结点的坐标,将其赋值为 X X ;如果他们 i s C o n n e c t e d isConnected ,那么不处理网格上的点。
  • 需要添加一个整形参数 t o t a l N o d e totalNode U F UF 构造方法。其最小值为网格 g r i d grid 数量 + 1 +1 。(数组下标边界问题)
class Solution {
  public void solve(char[][] board) {
    if(board.length == 0 || board == null)  return;
    
    // 核心思想:处理边界上的 '0'
    int rows = board.length;
    int cols = board[0].length;
    int N = rows * cols;
    int staticVal = 0;
    UF uf = new UF(N+1);

    for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
    if(board[i][j] == 'O') {
      int t = i * cols + j;
      if(i == 0 || i == rows-1 || j == 0 || j == cols-1)
        uf.union(t, staticVal);
      else {
        int u = i-1, d = i+1, l = j-1, r = j+1;
        if(board[u][j] == 'O') uf.union(t, u*cols + j);
        if(board[d][j] == 'O') uf.union(t, d*cols + j);
        if(board[i][l] == 'O') uf.union(t, i*cols + l);
        if(board[i][r] == 'O') uf.union(t, i*cols + r);
      }
    }
    // 关键代码
    for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++){
      if(!uf.isConnected(i*cols + j, staticVal))
        board[i][j] = 'X';
    }
  }
  
  class UF {
    private int[] parent;
    private int[] rank;

    public UF(int totalNodes) {
      parent = new int[totalNodes];
      rank = new int[totalNodes];
      for(int i = 0; i < totalNodes; i++) {
        parent[i] = i;
        rank[i]=0;
      }
    }

    // 找到结点p对应的组
    public int find(int p) {
      if(p < 0 || p > parent.length)
        throw new IllegalArgumentException("p is out of bound");
      // 路径压缩
      while(p != parent[p]) {
        parent[p] = parent[parent[p]];
        p = parent[p];
      }
      return p;
    }

    public boolean isConnected(int p, int q) {
      return find(p) == find(q);
    }

    public void union(int p, int q) {
      int pRootID = find(p);
      int qRootID = find(q);

      if(pRootID == qRootID)  return;

      if(rank[pRootID] > rank[qRootID])
        parent[qRootID] = pRootID;
      else if(rank[pRootID] < rank[pRootID])
        parent[pRootID] = qRootID;
      else {
        parent[pRootID] = qRootID;
        rank[qRootID]++;  // 深度加一
      }
      // count--;
    }
  }
}

复杂度分析

  • 时间复杂度: O ( O 2 ) O(O^2)
  • 空间复杂度: O ( 2 M N ) O(2*M*N)
发布了300 篇原创文章 · 获赞 48 · 访问量 8042

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104060072