leetCode130:被圍繞的區域
阿新 • • 發佈:2021-01-06
技術標籤:刷題筆記
目錄
一、題目描述
給定一個二維的矩陣,包含'X'和'O'(字母 O)。
找到所有被 'X' 圍繞的區域,並將這些區域裡所有的'O' 用 'X' 填充。
示例:
X X X X
X O O X
X X O X
X O X X
執行你的函式後,矩陣變為:
X X X X
X X X X
X X X X
X O X X
解釋:
被圍繞的區間不會存在於邊界上,換句話說,任何邊界上的'O'都不會被填充為'X'。 任何不在邊界上,或不與邊界上的'O'相連的'O'最終都會被填充為'X'。如果兩個元素在水平或垂直方向相鄰,則稱它們是“相連”的。
二、解題思路
思路還是比較直接的,這類題在圖和並查集當中屬於一類很經典的題目。本質是求連通分量的個數。
通常這類題都有三種解法:
- 深度優先搜尋
- 廣度優先搜尋
- 並查集
深度或廣度搜索進行的次數即為連通塊的數量;並查集則為最後有幾個集合則有多少個連通塊。
對於leetCode200來說,上面所說的做法就可以解決了。但是這一題不同的地方在於在邊界上的'O'連通塊是不用處理的,所以只需要把處於邊界的連通塊遍歷出來即可。除了邊界的連通塊,其餘地方的'O'全部改為'X'。
三、程式碼實現
內含轉載大佬程式碼:
作者:liweiwei1419
連結:https://leetcode-cn.com/problems/surrounded-regions/solution/dfs-bing-cha-ji-java-by-liweiwei1419/
//本人寫的dfs #include<bits/stdc++.h> using namespace std; //遍歷的四個方向 vector<int> dx = { 0,0,1,-1 }; vector<int> dy = { 1,-1,0,0 }; void dfs(int m, int n, vector<vector<bool>>& visited, vector<vector<char>>& board) { visited[m][n] = true; for (int i = 0; i < 4; i++) { int x = m + dx[i]; int y = n + dy[i]; if (x >= 0 && x < board.size() && y >= 0 && y < board[0].size()) { if (board[x][y] == 'O' && !visited[x][y]) { dfs(x, y, visited, board); } } } } void solve(vector<vector<char>>& board) { int m = board.size(); if (m == 0) { return; } int n = board[0].size(); vector < vector <bool>> visited(m, vector<bool>(n, false)); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { //在最外圍的位置 if (i == 0 || (i != 0 && (j == 0 || j == n - 1)) || i == m - 1) { if (board[i][j] == 'O' && !visited[i][j]) { dfs(i, j, visited, board); } } } } //把所有沒有被訪問且為'O'的位置改掉 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!visited[i][j] && board[i][j] == 'O') { board[i][j] = 'X'; } } } } int main() { vector<vector<char>> board = { {'X','X','X','X','X'}, {'X','O','O','O','X'}, {'X','X','X','O','X'}, {'X','X','O','X','X'}, {'X','X','O','X','X'} }; solve(board); for (auto x : board) { cout << x[0] << " " << x[1] << " " << x[2] << " " << x[3] << " " << x[4] << endl; } return 0; } //題解區大佬寫的bfs和並查集(java),作者:liweiwei1419 import java.util.LinkedList; import java.util.Queue; public class Solution { public void solve(char[][] board) { int rows = board.length; if (rows == 0) { return; } int cols = board[0].length; int[][] directions = new int[][]{{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; // 第 1 步:把四周的 'O' 全部推入佇列,通過廣度優先遍歷,把與 'O' 連通的地方全部編輯 Queue<int[]> queue = new LinkedList<>(); for (int i = 0; i < rows; i++) { if (board[i][0] == 'O') { queue.offer(new int[]{i, 0}); } if (board[i][cols - 1] == 'O') { queue.offer(new int[]{i, cols - 1}); } } for (int j = 1; j < cols - 1; j++) { if (board[0][j] == 'O') { queue.offer(new int[]{0, j}); } if (board[rows - 1][j] == 'O') { queue.offer(new int[]{rows - 1, j}); } } while (!queue.isEmpty()) { int[] top = queue.poll(); int i = top[0]; int j = top[1]; board[i][j] = '-'; for (int[] direction : directions) { int newX = i + direction[0]; int newY = j + direction[1]; if (inArea(newX, newY, rows, cols) && board[newX][newY] == 'O') { queue.offer(new int[]{newX, newY}); } } } // 第 2 步:恢復 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (board[i][j] == '-') { board[i][j] = 'O'; } else if (board[i][j] == 'O') { board[i][j] = 'X'; } } } } private boolean inArea(int x, int y, int rows, int cols) { return x >= 0 && x < rows && y >= 0 && y < cols; } } //並查集 public class Solution { public void solve(char[][] board) { int rows = board.length; if (rows == 0) { return; } int cols = board[0].length; if (cols == 0) { return; } UnionFind unionFind = new UnionFind(rows * cols + 1); int dummyNode = rows * cols; // 填寫第 1 行和最後一行 for (int j = 0; j < cols; j++) { if (board[0][j] == 'O') { unionFind.union(getIndex(0, j, cols), dummyNode); } if (board[rows - 1][j] == 'O') { unionFind.union(getIndex(rows - 1, j, cols), dummyNode); } } // 填寫第 1 列和最後一列 for (int i = 1; i < rows - 1; i++) { if (board[i][0] == 'O') { unionFind.union(getIndex(i, 0, cols), dummyNode); } if (board[i][cols - 1] == 'O') { unionFind.union(getIndex(i, cols - 1, cols), dummyNode); } } int[][] directions = new int[][]{{0, 1}, {1, 0}}; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (board[i][j] == 'O') { for (int[] direction : directions) { int newX = i + direction[0]; int newY = j + direction[1]; if (newX < rows && newY < cols && board[newX][newY] == 'O') { unionFind.union(getIndex(i, j, cols), getIndex(newX, newY, cols)); } } } } } for (int i = 1; i < rows - 1; i++) { for (int j = 0; j < cols - 1; j++) { if (board[i][j] == 'O') { if (!unionFind.isConnected(getIndex(i, j, cols), dummyNode)) { board[i][j] = 'X'; } } } } } private int getIndex(int x, int y, int cols) { return x * cols + y; } class UnionFind { private int[] parent; public UnionFind(int n) { this.parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } } public boolean isConnected(int x, int y) { return find(x) == find(y); } public int find(int x) { while (x != parent[x]) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; } public void union(int x, int y) { int xRoot = find(x); int yRoot = find(y); if (xRoot == yRoot) { return; } parent[xRoot] = yRoot; } } }