一:被围绕的区域
解题关键:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O'都不会被填充为 'X'
法一: dfs
这里的O有两种:一种是和边界相连的,一种是被X环绕着
说白了,只要O和边界上的是连通的(上下左右可到达),这个O最后不会被还原
思路:
从边界出发(即四边的两行两列),然后dfs把所有O用A标记,表示这个O不可以被X代替,然后还原棋盘,即---A还原O,O还原X
class Solution { private: int m,n;//m是长,n是宽 int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//四个方向 bool isInArea(int i,int j){ return i>=0&&i<m&&j>=0&&j<n;} void dfsMark_A(vector<vector<char>>& board,int x,int y){ //dfs---把与边界相连的O标记成A if(!isInArea(x,y)||board[x][y]=='X'||board[x][y]=='A') return; board[x][y]='A'; for(int i=0;i<4;i++){ int newX=x+d[i][0]; int newY=y+d[i][1]; dfsMark_A(board,newX,newY); } } public: void solve(vector<vector<char>>& board){ m=board.size(); if(m==0) return; n=board[0].size(); if(n==0) return; //从边界出发,开始dfs标记 for(int i=0;i<n;i++){ //确定两行 dfsMark_A(board,0,i); dfsMark_A(board,m-1,i); } for(int j=1;j<m-1;j++){ //确定两列 dfsMark_A(board,j,0); dfsMark_A(board,j,n-1); } //还原标志 for(int i=0;i<m;i++) for(int j=0;j<n;j++){ if(board[i][j]=='A') board[i][j]='O'; else if(board[i][j]=='O') board[i][j]='X'; } } };
一:主程序边界出发的两个语句
//从边界出发,开始dfs标记 for(int i=0;i<n;i++){ //确定两行 dfsMark_A(board,0,i); dfsMark_A(board,m-1,i); } for(int j=1;j<m-1;j++){ //确定两列 dfsMark_A(board,j,0); dfsMark_A(board,j,n-1); }
当然也可以先列后行
for(int i=0;i<m;i++){ //确定两列 dfsMark_A(board,i,0); dfsMark_A(board,i,n-1); } for(int j=1;j<n-1;j++){ //确定两行 dfsMark_A(board,0,j); dfsMark_A(board,m-1,j); }
二:dfs函数
void dfsMark_A(vector<vector<char>>& board,int x,int y){ //dfs---把与边界相连的O标记成A if(!isInArea(x,y)||board[x][y]=='X'||board[x][y]=='A') return; board[x][y]='A'; for(int i=0;i<4;i++){ int newX=x+d[i][0]; int newY=y+d[i][1]; dfsMark_A(board,newX,newY); } }
逻辑:
dfs{
如果不符合条件(不在区域内 或 当前元素不是O) return;
//开始
当前符号记作‘A’
四个方向查找
}
正向思维:
class Solution { private: int m,n;//m是长,n是宽 int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//四个方向 bool isInArea(int i,int j){ return i>=0&&i<m&&j>=0&&j<n;} void dfsMark_A(vector<vector<char>>& board,int x,int y){ //dfs---把与边界相连的O标记成A board[x][y]='A'; for(int i=0;i<4;i++){ int newX=x+d[i][0]; int newY=y+d[i][1]; if(isInArea(newX,newY)&&board[newX][newY]=='O'){ dfsMark_A(board,newX,newY);} } return; } public: void solve(vector<vector<char>>& board){ m=board.size(); if(m==0) return; n=board[0].size(); if(n==0) return; //从边界出发,开始dfs标记 for(int i=0;i<m;i++){ //确定两列 if(board[i][0]=='O') dfsMark_A(board,i,0); if(board[i][n-1]=='O') dfsMark_A(board,i,n-1); } for(int j=1;j<n-1;j++){ //确定两行 if(board[0][j]=='O') dfsMark_A(board,0,j); if(board[m-1][j]=='O') dfsMark_A(board,m-1,j); } //还原标志 for(int i=0;i<m;i++) for(int j=0;j<n;j++){ if(board[i][j]=='A') board[i][j]='O'; else if(board[i][j]=='O') board[i][j]='X'; } } };
关键在递归前必须保证---岛屿的值是O
for(int i=0;i<m;i++){
//确定两列
if(board[i][0]=='O')
dfsMark_A(board,i,0);
if(board[i][n-1]=='O')
dfsMark_A(board,i,n-1);
}
for(int j=1;j<n-1;j++){
//确定两行
if(board[0][j]=='O')
dfsMark_A(board,0,j);
if(board[m-1][j]=='O')
dfsMark_A(board,m-1,j);
}class Solution { private: int m,n;//m是长,n是宽 int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//四个方向 bool isInArea(int i,int j){ return i>=0&&i<m&&j>=0&&j<n;} void dfsMark_A(vector<vector<char>>& board,int x,int y){ //dfs---把与边界相连的O标记成A if(board[x][y]!='O') return; board[x][y]='A'; for(int i=0;i<4;i++){ int newX=x+d[i][0]; int newY=y+d[i][1]; if(isInArea(newX,newY)&&board[newX][newY]=='O'){ dfsMark_A(board,newX,newY);} } return; } public: void solve(vector<vector<char>>& board){ m=board.size(); if(m==0) return; n=board[0].size(); if(n==0) return; //从边界出发,开始dfs标记 for(int i=0;i<m;i++){ //确定两列 dfsMark_A(board,i,0); dfsMark_A(board,i,n-1); } for(int j=1;j<n-1;j++){ //确定两行 dfsMark_A(board,0,j); dfsMark_A(board,m-1,j); } //还原标志 for(int i=0;i<m;i++) for(int j=0;j<n;j++){ if(board[i][j]=='A') board[i][j]='O'; else if(board[i][j]=='O') board[i][j]='X'; } } };
或者在标记成A之前检查一下