130. Surrounded Regions

一、题目

  1、审题

  

  2、分析

    给出一个二维数组,数组中只包含字符 'O'、‘X', 将数组中被 'X' 包围的 'O' 全部换成 'X'。(其中紧邻边界不算包围)

 

二、解答

  1、思路: 

    方法一、

      ①、将紧挨着棋盘边缘的 "O'" 或者与边缘的 "O" 连通的 “O” 全部换成 “1“;

      ②、将剩下的 O 全部换成 X,将 “1” 全部换成 “O“;

    public void solve(char[][] board) {
        int rows = board.length;
        if(rows < 3)
            return;
        int cols = board[0].length;
        if(cols < 3)
            return;
        
        for (int row = 0; row < rows; row++) {
            check(board, row, 0, rows, cols); // 第一列的每个元素
            check(board, row, cols - 1, rows, cols); // 最后一列的每个元素
        }
        
        for (int j = 1; j < cols - 1; j++) {
            check(board, 0, j, rows, cols);    // 第一行 (除了第一个、最后一个元素)
            check(board, rows - 1, j, rows, cols);  // 最后一行
        }
        
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < cols; j++) {
                if(board[i][j] == 'o')
                    board[i][j] = 'x';
                if(board[i][j] == '1')
                    board[i][j] = 'o';
                
                System.out.print(board[i][j]);
            }
            System.out.println();
        }
    }
    

    void check(char[][] board, int row, int col, int rows, int cols) {
        
        if(board[row][col] == 'o') {
            board[row][col] = '1';
            if(row > 1)
                check(board, row - 1, col, rows, cols);
            if(col > 1)
                check(board, row, col - 1, rows, cols);
            if(row < rows - 1)
                check(board, row + 1, col, rows, cols);
            if(col < cols - 1)
                check(board, row, col + 1, rows, cols);
        }
    }
    

 

    方法二、

      使用 Union Find(并查集) 。

      ①、采用并查集将所有边界的值为 ‘O’ 的节点与并查集中一个特殊值 oRoot 合并在同一集合中,且 oRoot 作为他们的头结点。

      ②、将非边界的值为 ‘O’ 的节点与该节点上下左右值为 ‘O’ 的节点进行合并。

      ③、遍历数组所有元素,若值为 ‘O’,判断是否和 oRoot 是同一集合,若不是,则元素值改为 'X',否则不变化。

public void solve(char[][] board) {
        
        if (board == null || board.length == 0 || board[0].length == 0)
            return;
        
        int rows = board.length;
        int cols = board[0].length;
        int oRoot = rows * cols;
        
        initUnionFind(rows * cols);
        
        for(int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if(board[i][j] == 'X')
                    continue;
                
                int cur = i * cols + j;
                if(i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {    
                    union(cur, oRoot); // 将边界中值为 ’O‘ 的节点全部 并到 oRoot 所在集合中
                }
                else {
                    // 非边界的值为 ’O‘ 节点与  上下左右  值为 'O'的节点合并。
                    if(j + 1 < cols && board[i][j + 1] == 'O')
                        union(cur, i * cols + j + 1);
                    if(j - 1 >= 0 && board[i][j - 1] == 'O')
                        union(cur, i * cols + j - 1);
                    if(i + 1 < rows && board[i + 1][j] == 'O')
                        union(cur, (i+1) * cols + j);
                    if(i - 1 >= 0 && board[i - 1][j] == 'O')
                        union(cur, (i - 1) * cols + j);
                }
            }
        }
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if(board[i][j] == 'O' && find(i * cols + j) != oRoot)
                    board[i][j] = 'X';
                
                System.out.print(board[i][j] + ", " );
            }
            System.out.println();
        }
    }
    
    int[] s;
    int[] rank;

    // 找到根节点
    private int find(int p) {
        
        while(s[p] != p)
            p = s[p];
        
        return p;
    }

    private void union(int p, int q) {
        
        int pRoot = find(p);
        int qRoot = find(q);
        
        if(pRoot == qRoot)    
            return;
        if(rank[pRoot] < rank[qRoot]) { //保证小的树在大的下面
            s[pRoot] = qRoot;
            rank[qRoot] += rank[pRoot];
        }
        else {
//            if(rank[pRoot] == rank[qRoot])
//                rank[pRoot]++;
            s[qRoot] = pRoot;
            rank[pRoot] += rank[qRoot];
        }
        
    }

    private void initUnionFind(int n) {
        s = new int[n + 1];
        rank = new int[n + 1];
        for(int i = 0; i <= n; i++)
            s[i] = i;
        rank[n] = n + 1;
    }

 

posted @ 2018-10-08 13:28  skillking2  阅读(99)  评论(0编辑  收藏  举报