前阵子参加了,字节跳动的面试,面试官给出了一道算法题,题目虽然不难,但不知道怎么,当时也没作出来,如今回头再作一次。该算法题其实就是leetcode
上的130. Surrounded Regions
.javascript
Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by
'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
复制代码
Example:
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
复制代码
在面试时,我一开始的思路是直接找出被包围的O
,可是在后期实现的时候发现这种方式虽然可行,可是实现起来贼麻烦,判断特别多,很容易出错。后来,面试官提示我从侧面思考,找到全部未被X
包围的O
.java
O
要被包围的条件是上下左右都为X
,由此咱们能够推出边界上的O
确定不会被包围。被包围的O
只可能出如今内部。python
找到全部未被包围的O
,而后将剩下的O
所有变为1
.面试
那么如何找到全部未被包围的O
呢?经过前面的分析,咱们能够知道边界上的O
确定是未被包围的,因此,咱们能够从这里入手。到了这里,咱们就很容易想到使用floodfill
算法。算法
针对上面的例子而言,要找出全部被包围的O
,对每个节点的访问是必不可免的。咱们很容易想到双重循环:数组
for(let i=0;i<grid.length;i++){
for(let j=0;j<grid[i].length;j++){
// do something on grid[i][j]
}
}
复制代码
经过上面的分析,咱们知道不被包围的O
确定是出如今边界的。bash
咱们简单来举几个例子:ui
X X O X X X X X X X O X
一 O O O X 二 X O O X 三 X 0 0 X
X O X X X O O X X 0 0 X
X O X X X X X X X X X X
复制代码
对于一
来讲,当咱们访问到grid[0][2]
的时候,咱们发现grid[0][2]=='O'
,基于此,咱们在这里开始采用floodfill
算法。spa
算法思路以下:code
grid[i][j]==='O'
,咱们首先要用一种标识表示,当前位置咱们已经访问过。grid
规模形状相同的二维数组对每个元素是否访问过作标识,另外一种是在原地作标识。
let hasVisited = new Array(grid.length).fill(new Array(grid[0].length).fill(0))
...// some logics
if(grid[i][j]==='O' && hasVisited==0){ //当前节点为`O`,并且以前未被访问过
hasVisited==1
}
复制代码
*
,这样咱们就知道咱们以前有没有访问过了。if(grid[i][j]=='O'){
grid[i][j]='*'
}
复制代码
grid[i][j]=='O'
的位置开始floodfill
算法。floodfill
的算法其实很简单,就是从当前位置开始,向上、下、左、右
四个位置开始进行染色
,若是该位置是O
,咱们一样将其标识为*
, 对于上面的例子来讲,最终结果为:X X * X X X X X X X * X
一 * * * X 二 X O O X 三 X * * X
X * X X X O O X X * * X
X * X X X X X X X X X X
复制代码
咱们发现第二个例子并无发生变化,若是O
要想不被包围,那么其边界上必定要有O
.
for(let i=0;i<grid.length;i++){
for(let j=0;j<grid[i].length;j++){
// do something on grid[i][j]
if(i===0 || i===grid.length-1 || j===0 || j===grid[i].length){
if(grid[i][j]==='O'){//floodfill
dfs(grid,i,j)
}
}
}
}
复制代码
解题代码:
var solve = function (board) {
let m = board.length;
let n = board[0] ? board[0].length : 0
if (m === 0 || n === 0) {
return;
}
let map = [[-1, 0], [0, 1], [1, 0], [0, -1]]
function dfs(board, x, y) {
if (x < 0 || x >= m || y < 0 || y >= n || board[x][y] !== 'O' ) {// out of boundary
return;
}
if(board[x][y] == 'O'){
board[x][y] = '*'
for (let i = 0; i < 4; i++) {
dfs(board, x + map[i][0], y + map[i][1])
}
}
// return;
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if ((i == 0 || i == m - 1 || j == 0 || j == n - 1) && board[i][j] === 'O') {
dfs(board, i, j)
}
}
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
board[i][j] = board[i][j] === '*'?'O':'X'
}
}
};
复制代码
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
directions = [[-1, 0], [1, 0], [0, 1], [0, -1]]
m = len(board)
if m == 0:
return;
n = len(board[0])
if n == 0:
return;
def dfs(board, x, y):
if(x < 0 or x >= m or y < 0 or y >= n or board[x][y] != 'O'):
return
if board[x][y] == 'O':
board[x][y] = '*'
for i in range(4):
dfs(board, x+directions[i][0], y+directions[i][1])
for i in range(m):
for j in range(n):
if(i == 0 or i == m-1 or j == 0 or j == n-1) and board[i][j] == 'O':
dfs(board, i, j)
for i in range(m):
for j in range(n):
board[i][j] = 'O' if board[i][j]=='*' else 'X'
复制代码
class Solution {
private int m,n;
private int[][] map={{-1,0},{0,1},{1,0},{0,-1}};
public void solve(char[][] board) {
m = board.length;
if(m==0){
return;
}
n = board[0].length;
if(n==0){
return;
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if (i == 0 || i == m - 1 || j == 0 || j == n - 1){
if(board[i][j]=='O'){
dfs(board,i,j);
}
}
}
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
board[i][j]=board[i][j]=='*'?'O':'X';
}
}
}
private void dfs(char[][] board,int x,int y){
if(x<0 || x>=m || y<0 || y>=n || board[x][y]!='O'){
return;
}
if(board[x][y]=='O'){
board[x][y]='*';
for(int i=0;i<4;i++){
dfs(board,x+map[i][0],y+map[i][1]);
}
}
}
}
复制代码