一起刷LeetCode——被围绕的区域(并查集)

174 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

最近很少有并查集的题目,偶尔翻到之前使用DFS解决的一道题目,这道题目或许可以尝试使用并查集来解

被围绕的区域

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

来源:leetcode.cn/problems/su…

分析

DFS或BFS

  • 如果使用DFS或者BFS来分析这道题目,思路是通过不断地搜索,搜索到O的时候,分情况,如果是在边界,把O改为S,如果不是边界,把O改为X,最后把S改为X,此时的矩阵就是答案

并查集

  • 首先简单介绍一下并查集:并查集是一种很优雅的树型结构,一般用来描述不相交集合的合并和查询,合并指的是把不相交的集合合并成一个,查询是查询两个元素是否在一个集合中
  • 首先要实现一个并查集,包括矩阵为参数的初始化、合并、查询
  • 设置一个傀儡节点,遍历整个矩阵,遍历到字符O,当字符O在边界时,这个字符和傀儡节点相连,如果不在边界就和相邻的节点相连
  • 再次遍历矩阵,如果O和傀儡节点相连,就不变,如果不是就改为X,就是的矩阵就是答案
  • 优化:因为矩阵中的元素和其坐标有相关性,可以把二维化为一位,id用x_y来表示,数据结构更优美

代码

/**
 * @param {character[][]} board
 * @return {void} Do not return anything, modify board in-place instead.
 */
var solve = function(board) {
    const DIRS = [[0, 1], [0, -1], [1, 0], [-1, 0]]; 
    if (board === null || board.length === 0) return;

    let rows = board.length;
    let cols = board[0].length;

    const UnionFind = function(board){
        let parent = {};

        for (let x=0; x<rows; x++){
            for (let y=0; y<cols; y++){
                if (board[x][y] === 'O') {
                    let id = `${x}_${y}`;
                    parent[id] = id;
                }
            }
        }
        parent['dummy'] = 'dummy';

        this.find = (x) => {
            if (x === parent[x]) return x;
            parent[x] = this.find(parent[x]);
            return parent[x];
        }

        this.union = (x, y) => {
            let rootX = this.find(x);
            let rootY = this.find(y);
            if (rootX !== rootY){
                parent[rootX] = rootY;
            }
        }
    }

    let uf = new UnionFind(board);
    let dummyBorder = 'dummy';

    for (let x=0; x<rows; x++){
        for (let y=0; y<cols; y++){
            if (board[x][y] === 'O'){
                let id = `${x}_${y}`;
                if (x === 0 || x === rows-1 || y === 0 || y === cols-1){
                    uf.union(dummyBorder, id);
                }
                for (let dir of DIRS){
                    let nx = x + dir[0];
                    let ny = y + dir[1];
                    if (nx >= 0 && ny >=0 && nx < rows && ny < cols && board[nx][ny] === 'O'){
                        let nId = `${nx}_${ny}`;
                        uf.union(id, nId);
                    }
                }
            }
        }
    }
    for (let x = 0; x < rows; x++) {
        for (let y = 0; y < cols; y++) {
            if (board[x][y] === 'O' && uf.find(`${x}_${y}`) !== uf.find(dummyBorder)) {
                board[x][y] = 'X';
            }
        }
    }
};

总结

  • 并查集作为一种特殊的数据结构在算法的宇宙中不算突出,但是却能给我们解决问题带来新的灵感,当题目中如果有连同、查找同时存在的操作时,不妨试试并查集
  • 今天也是有收获的一天