Surrounded Regions
Given a 2D board containing 'X'
and 'O'
, capture all regions surrounded by 'X'
.
A region is captured by flipping all 'O'
s into 'X'
s in that surrounded region .
For 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
思路:典型的DFS问题,从有"O"的位置开始搜索,如果到了边界遇到了'O',返回false. 但很大的board的时候,栈溢出了。所以,需要改成BFS,一下算法给出DFS和BFS的实现
总结:1、DFS 的优势能给出路径 但是栈容易溢出 2、DFS的一进去判断递归出口(当前已经含有路径的全部信息,想想PalindromePartition I问题,遍历完了整个字符串) 然后设置visit 然后访问。DFS有PreVisit和PostVisit两处位置
3、BFS在入队列的时候,就将visit置位(以防别人也将这个元素放入到队列) 然后进行访问。当然,从队列里面出来也可以访问。
心得:题目虽然不难,但是坑不少,尤其是设立状态位还是直接返回,还有边界的问题
#include <iostream> #include <vector> #include <queue> using namespace std; #define MAXN 1024 class Solution { public: //board遍历的过程中,如果被update了,那也oK bool dfs(const vector<vector<char> > &board, int x, int y){ int dx[] = {0,-1,0,1}; int dy[] = {-1,0,1,0}; //DFS函数一进来做递归出口判断,visit,访问元素 PreVisit if (x <= 0 || x >= m - 1 || y <= 0 || y >= m -1){ //为0才进递归,所以不需要再判断是否是 '0' return false; } m_block.push_back(x*m + y); m_visit[x*m + y] = 1; //四个方向都访问OK,之后返回OK //其中一个方向错误,就会直接return for(int i = 0; i < 4; i++){ int di = x + dx[i]; int dj = y + dy[i]; int z = di*m + dj; if (!m_visit[z] && board[di][dj] == 'O'){ bool ret = dfs(board,di,dj); //m_visit[z] = 1; 这个visit放在哪里,是很很有讲究的 visit放在这里,就会死循环,这个位置和BFS不同 if (!ret){ return false; } } } //DFS 在此处可以做PostVisit 也就是一条路径向下回来之后再访问当前元素 return true; } //BFS版本AC bool bfs(const vector<vector<char> > &board, int x, int y){ int dx[] = {0,-1,0,1}; int dy[] = {-1,0,1,0}; std::queue<int> qu; int z = x*m + y; m_block.push_back(z); qu.push(z); m_visit[z] = 1; bool status_yes = true; while(!qu.empty()){ int pos = qu.front(); qu.pop(); x = pos/m; y = pos%m; //其中一个方向错误,就会直接return for(int i = 0; i < 4; i++){ int di = x + dx[i]; int dj = y + dy[i]; int z = di*m + dj; //到达边界并且是'O' if (di < 0 || di > m -1 || dj < 0 || dj > m -1){ continue; }else if (di == 0 || di == m-1 || dj == 0 || dj == m -1){ if (!m_visit[z] && board[di][dj] == 'O'){ m_visit[z] = 1; //即使返回false,当前位置也应该Visit=1 qu.push(z); status_yes = false; //即使状态不符合,也不能提前退出,要把当前的块全部遍历完。 //DFS应该也有一样的问题,设置一个标志位,而不是提前退出 //return false; } }else if (!m_visit[z] && board[di][dj] == 'O'){ m_visit[z] = 1; //进队列之前,就需要 visit = 1 并且访问元素,而不是等到出队列的时候访问 m_block.push_back(z); //这点和DFS visit的位置以及访问的方式不同 qu.push(z); } } } return status_yes; } void solve(vector<vector<char> > &board) { // Start typing your C/C++ solution below // DO NOT write int main() function /** X X X X X X X X X O O X --> X X X X X X O X X X X X X O X X X O X X 思路:dfs或者bfs遍历,从0出发,如果最后遍历没有到达边界,合法,全部变为X,中间保存块的下标位置 */ m = board.size(); if (!m){ return; } m_visit.clear(); m_visit.resize(m*m,0); m_block.clear(); //为了不越界,外边不走边界 for(size_t i = 1; i < board.size() -1; i++){ for(size_t j = 1; j < board.size() -1; j++){ int z = i * m + j; if (!m_visit[z] && board[i][j] == 'O'){ //bool ok = dfs(board,i,j); bool ok = bfs(board,i,j); if (ok){ //当前的出发合法 for(size_t k = 0; k < m_block.size(); k++){ int di = m_block[k]/m,dj = m_block[k]%m; board[di][dj] = 'X'; } } m_block.clear(); //合法或者不合法,都需要m_block.clear(); } } } } vector<int> m_block; vector<int> m_visit; int m; }; using namespace std; int main(int argc, char *argv[]) { /* char a[] = {'X','O','X','X'}; char b[] = {'O','X','O','X'}; char c[] = {'X','O','X','O'}; char d[] = {'O','X','O','X'}; vector<char> v1(a,a+4); vector<char> v2(b,b+4); vector<char> v3(c,c+4); vector<char> v4(d,d+4); */ char a[] = {'O','O','O'}; char b[] = {'O','O','O'}; char c[] = {'O','O','O'}; vector<char> v1(a,a+3); vector<char> v2(b,b+3); vector<char> v3(c,c+3); vector<vector<char> > board; board.push_back(v1); board.push_back(v2); board.push_back(v3); Solution sol; sol.solve(board); for(size_t i = 0; i < board.size(); i++){ for(size_t j = 0; j < board.size(); j++){ printf("%c",board[i][j]); } printf("\n"); } }