surrounded regions java,字节跳动面试算法题【Surrounded Regions】

前言

前阵子参加了,字节跳动的面试,面试官给出了一道算法题,题目虽然不难,但不知道怎么,当时也没做出来,现在回头再做一次。该算法题其实就是leetcode上的130. Surrounded Regions.

题目描述

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.

O要被包围的条件是上下左右都为X,由此我们可以推出边界上的O肯定不会被包围。被包围的O只可能出现在内部。

找到所有未被包围的O,然后将剩下的O全部变为1.

那么如何找到所有未被包围的O呢?通过前面的分析,我们可以知道边界上的O肯定是未被包围的,所以,我们可以从这里入手。到了这里,我们就很容易想到使用floodfill算法。

代码实现

针对上面的例子而言,要找出所有被包围的O,对每一个节点的访问是必不可免的。我们很容易想到双重循环:

for(let i=0;i

for(let j=0;j

// do something on grid[i][j]

}

}

复制代码

通过上面的分析,我们知道不被包围的O肯定是出现在边界的。

我们简单来举几个例子:

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算法。

算法思路如下:

如果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

for(let j=0;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)

}

}

}

}

复制代码

解题代码:

javascript

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'

}

}

};

复制代码

python3

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'

复制代码

java

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

for(int j=0;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

for(int j=0;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]);

}

}

}

}

复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值