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; }