leetcode第130题被围绕的区域

31 阅读2分钟

题目: 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

三种解法

  • 并查集

/**
 * @param {character[][]} board
 * @return {void} Do not return anything, modify board in-place instead.
 */

class UnionFind {
  constructor (n) {
    // 记录连通分量
    this.num = n;
    //  节点 x 的节点是 parent[x] // 父节点指针初始指向自己
    this.parent = new Array(n).fill(0).map((val, i) => i);
    // 新增一个数组记录树的“重量”,最初每棵树只有一个节点,重量应该初始化 1
    this.size = new Array(n).fill(1);
  }
  // 返回某个节点 x 的根节点
  find (x) {
    while(this.parent[x] != x) {
      x = this.parent[x];
    }
    return x;
  }

  union (p, q) {
    let rootP = this.find(p);
    let rootQ = this.find(q);
    if (rootP == rootQ) return;
    // 将两棵树合并为一棵, 小树接到大树下面,较平衡
    if (this.size[rootP] > this.size[rootQ]) {
      this.parent[rootQ] = rootP;
      this.size[rootP] += this.size[rootQ];
    } else {
      this.parent[rootP] = rootQ;
      this.size[rootQ] += this.size[rootP];
    }
    // 两个分量合二为一
    this.num--;
  }
  // 如果节点p和q连通的话,它们一定拥有相同的根节点
  isConnected (p, q) {
    let rootP = this.find(p);
    let rootQ = this.find(q);
    return rootP == rootQ;
  }
  count () {
    return this.num;
  }
}
var solve = function(board) {
  if (!board.length) return;
  let m = board.length, n = board[0].length;
  let uf = new UnionFind(m * n + 1);
  let dummy = m * n;
  // 将首列和末列的 O 与 dummy 连通
  for (let 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(let j = 0; j < n; j++) {
    if(board[0][j] == 'O') uf.union(j, dummy);
    if(board[m-1][j] == 'O') uf.union(n * (m -1) + j, dummy);
  }
  // 方向数组 d 是上下左右搜索的常用手法
  let d = [
    [1, 0],
    [0, 1],
    [0, -1],
    [-1, 0]
  ];
  for(let i = 1; i < m - 1; i++) {
    for (let j = 1; j < n -1; j++) {
      // 将此 O 与上下左右的 O 连通
      if (board[i][j] == 'O') {
        for(let k = 0; k < 4; k++) {
          let x = i + d[k][0], y = j + d[k][1];
          if(board[x][y] == 'O') {
            uf.union(x * n + y, i * n +j);
          }
        }
      }
    }
  }
  // 所有不和 dummy 连通的 O,都要被替换
  for(let i = 1; i < m -1; i++) {
    for(let j = 1; j < n - 1; j++) {
      if(!uf.isConnected(dummy, i * n + j)) {
        board[i][j] = 'X';
      }
    }
  }
};
  • DFS 思路

var solve = function (board) {
  let rows = board.length, cols = board[0].length;
  let directions = [
    [0, 1],
    [0, -1],
    [-1, 0],
    [1, 0]
  ];
  const dfs = (i, j) => {
    if (i < 0 || j < 0 || i >= rows || j >= cols ||
      board[i][j] != 'O' || board[i][j] == 'A') {
        return;
    }
    board[i][j] = 'A';
    for (let [x, y] of directions) {
      dfs(i + x, j +y);
    }
  }
  for (let i = 0; i < cols; i++) {
    if (board[0][i] == 'O') dfs(0, i);
    if (board[rows - 1][i] == 'O') dfs(rows - 1, i);
  }
  for (let i = 0; i < rows; i++) {
    // 第1列和最后一列
    if (board[i][0] == "O") dfs(i, 0);
    if (board[i][cols - 1] == "O") dfs(i, cols - 1);
  }
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      if (board[i][j] == "A") {
        board[i][j] = "O";
      } else if (board[i][j] == "O") {
        board[i][j] = "X";
      }
    }
  }
}
  • BFS思路

var solve = function (board) {
  let rows = board.length,
    cols = board[0].length;
  // 方向数组
  let directions = [
    [0, 1],
    [0, -1],
    [-1, 0],
    [1, 0],
  ];
  const bfs = (i, j) => {
    let queue = [[i, j]];
    while (queue.length) {
      let size = queue.length;
      while (size--) {
        let [x, y] = queue.shift();
        if (
          x < 0 ||
          y < 0 ||
          x >= rows ||
          y >= cols ||
          board[x][y] != "O" ||
          board[x][y] == "A"
        )
          continue;
        board[x][y] = "A";
        for (let [curI, curJ] of directions) {
          queue.push([curI + x, curJ + y]);
        }
      }
    }
  };
  for (let i = 0; i < cols; i++) {
    // 第1行和最后一行
    if (board[0][i] == "O") bfs(0, i);
    if (board[rows - 1][i] == "O") bfs(rows - 1, i);
  }
  for (let i = 0; i < rows; i++) {
    // 第1列和最后一列
    if (board[i][0] == "O") bfs(i, 0);
    if (board[i][cols - 1] == "O") bfs(i, cols - 1);
  }
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      if (board[i][j] == "A") {
        board[i][j] = "O";
      } else if (board[i][j] == "O") {
        board[i][j] = "X";
      }
    }
  }
};