zoukankan      html  css  js  c++  java
  • 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;
        }
  • 相关阅读:
    Django框架第九篇--Django和Ajax、序列化组件(serializers)、自定义分页器、模型表choice参数
    Django框架之第五篇(模板层) --变量、过滤器(|)、标签(% %)、自定义标签、过滤器、inclusion_tag,模板的继承、模板的注入、静态文件
    Django框架学习易错和易忘点
    守护线程
    Thread其他属性和方法
    进程与线程的区别
    开启线程
    关闭屏幕输出分屏显示
    生产者消费者模型
    队列
  • 原文地址:https://www.cnblogs.com/skillking/p/9753813.html
Copyright © 2011-2022 走看看