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
Explanation:
Surrounded regions shouldn’t be on the border, which means that any 'O'
on the border of the board are not flipped to 'X'
. Any 'O'
that is not on the border and it is not connected to an 'O'
on the border will be flipped to 'X'
. Two cells are connected if they are adjacent cells connected horizontally or vertically.
题目链接:https://leetcode-cn.com/problems/surrounded-regions/
思路
一开始觉得和数岛屿个数的题思路一致,每个点依赖于周围点的情况,递归到最后一个点发现符合条件后开始改变值并向上传递。于是有了下面的代码。
万万没想到,这道题会出bug,样例是:
[["X","X","X","X","O","X"],
["O","X","X","O","O","X"],
["X","O","X","O","O","O"],
["X","O","O","O","X","O"],
["O","O","X","X","O","X"],
["X","O","X","O","X","X"]]
如果在边界遇到不变化的O值后停止,不向内扩散相邻的不改变的O,那么由于遍历顺序的原因,内部的O可能还会误改变。
这个样例 从(1,3)开始向周围节点确定时,先向上、左确定后,开始向下走,经过(2,3)(3,3)(3,2)(3,1),到了(2,1)时,这里直接判定满足条件并变化了,但实际上接着递归(3,1)(4,1),到(4,0)发现不对劲,不能改变O,但是前面的(2,1)已经无法回去了。
class Solution {
public:
vector<vector<int>> visit;
void solve(vector<vector<char>>& board) {
int num = board.size();
if(!num) return;
int len = board[0].size();
visit = vector<vector<int>>(num, vector<int>(len, 0));
for(int i=0; i<num; ++i){
for(int j=0; j<len; ++j){
if(board[i][j]=='O' )
if(visit[i][j]==0) change(board, i, j);
}
}
}
bool change(vector<vector<char>>& board, int row, int col){
int num = board.size(), len = board[0].size();
int res = 0;
if (board[row][col]=='X' ){
return true;
}
if(row==0 || row==num-1 || col==0 || col==len-1 || visit[row][col]==2){
visit[row][col] = 2;
return false;
}
if(visit[row][col]==1) {
return true;
}
else{
visit[row][col] = 1;
if(change(board, row-1, col)) ++res;
else{
visit[row][col] = 2;
return false;
}
if(change(board, row, col-1)) ++res;
else {
visit[row][col] = 2;
return false;
}
if(change(board, row+1, col)) ++res;
else {
visit[row][col] = 2;
return false;
}
if(change(board, row, col+1)) ++res;
else {
visit[row][col] = 2;
return false;
}
}
if(res==4){
visit[row][col] == 1;
board[row][col] = 'X';
return true;
}
visit[row][col] = 2;
return false;
}
};
因此我们改变策略,改成先检查四周上的点,遇到O就周围寻找相邻的点,叫他们不许动;检查查完剩下的O都是在内部的,这些点是需要改变的。
class Solution {
public:
void solve(vector<vector<char>>& board) {
int num = board.size();
if(!num) return;
int len = board[0].size();
int is[] = {0, num-1}, js[] = {0, len-1};
for(int i=0; i<2; ++i){
for(int j = 0; j<len; ++j){
if(board[is[i]][j]=='O') change(board, is[i], j);
}
}
for(int j = 0; j<2; ++j){
for(int i=1; i<num-1; ++i){
if(board[i][js[j]]=='O') {
change(board, i, js[j]);
}
}
}
for(int i=0; i<num; ++i){
for(int j=0; j<len; ++j){
if (board[i][j]=='#'){
board[i][j] = 'O';
}
else if (board[i][j]=='O'){
board[i][j] = 'X';
}
}
}
}
void change(vector<vector<char>>& board, int row, int col){
if(board[row][col]=='O') {
board[row][col] = '#';
}
else return;
if(row-1>=0) {
change(board, row-1, col);
}
if(col-1>=0) {
change(board, row, col-1);
}
if(row+1<board.size()) {
change(board, row+1, col);
}
if(col+1<board[0].size()) {
change(board, row, col+1);
}
}
};