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");
    }
}

 

 

 



posted @ 2013-06-12 17:15  一只会思考的猪  阅读(225)  评论(0编辑  收藏  举报