Wednesday, December 3, 2014

Surrounded Regions

from codeganker
这个题目用到的方法是图形学中的一个常用方法:Flood fill算法,其实就是从一个点出发对周围区域进行目标颜色的填充。背后的思想就是把一个矩阵看成一个图的结构,每个点看成结点,而边则是他上下左右的相邻点,然后进行一次广度或者深度优先搜索。
接下来我们看看这个题如何用Flood fill算法来解决。首先根据题目要求,边缘上的'O'是不需要填充的,所以我们的办法是对上下左右边缘做Flood fill算法, 把所有边缘上的'O'都替换成另一个字符,比如'#'。接下来我们知道除去被我们换成'#'的那些顶点,剩下的所有'O'都应该被替换成'X',而'#' 那些最终应该是还原成'O',如此我们可以做最后一次遍历,然后做相应的字符替换就可以了。复杂度分析上,我们先对边缘做Flood fill算法, 因为只有是'O'才会进行,而且会被替换成'#',所以每个结点改变次数不会超过一次,因而是O(m*n)的复杂度,最后一次遍历同样是O(m*n),所 以总的时间复杂度是O(m*n)。空间上就是递归栈(深度优先搜索)或者是队列(广度优先搜索)的空间,同时存在的空间占用不会超过O(m+n)(以广度 优先搜索为例,每次队列中的结点虽然会往四个方向拓展,但是事实上这些结点会有很多重复,假设从中点出发,可以想象最大的扩展不会超过一个菱形,也就是 n/2*2+m/2*2=m+n,所以算法的空间复杂度是O(m+n))。

class Solution {
public:
    void solve(vector<vector<char>> & board) {
    if(board.size()<=1 || board[0].size()<=1)
        return;
    for(int i=0;i<board[0].size();i++)
    {
        fill(board,0,i);
        fill(board,board.size()-1,i);
    }
    for(int i=0;i<board.size();i++)
    {
        fill(board,i,0);
        fill(board,i,board[0].size()-1);
    }
    for(int i=0;i<board.size();i++)
    {
        for(int j=0;j<board[0].size();j++)
        {
            if(board[i][j]=='O')
                board[i][j]='X';
            else if(board[i][j]=='#')
                board[i][j]='O';               
        }
    }
}
void fill(vector<vector<char>> & board, int i, int j)
{
    if(board[i][j]!='O')
        return;
    board[i][j] = '#';
    queue<int> queue;
    int code = i*board[0].size()+j;
    const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    queue.push(code);
    while(!queue.empty())
    {
        code = queue.front();queue.pop();
        int row = code/board[0].size();
        int col = code%board[0].size();
        for(int i=0;i<4;i++){
            int currow=row+dir[i][0];
            int curcol=col+dir[i][1];
            if(currow>=0&&currow<board.size()&&curcol>=0&&curcol<board[0].size()){
                if(board[currow][curcol]=='O'){
                    board[currow][curcol]='#';
                    queue.push(currow*board[0].size()+curcol);
                }
            }
        }
       
    }
}
};

//another flavor, from anniekim
class Solution {
public:
    typedef vector<vector<char> > BOARDTYPE;
   
    void solve(BOARDTYPE &board) {
        if (board.empty() || board[0].empty()) return;
        int N = board.size(), M = board[0].size();
        for (int i = 0; i < N; ++i)
            for (int j = 0; j < M; ++j)
                if (i == 0 || j == 0 || i == N-1 || j == M-1)
                    bfs(board, i, j); // you may call dfs or bfs here!
        for (int i = 0; i < N; ++i)
            for (int j = 0; j < M; ++j)
                board[i][j] = (board[i][j] == 'V') ? 'O' : 'X';
    }
   
    void dfs(BOARDTYPE &board, int row, int col) {
        int N = board.size(), M = board[0].size();
        if (row < 0 || row >= N || col < 0 || col >= M) return;
        if (board[row][col] != 'O') return;
        board[row][col] = 'V';
        dfs(board, row+1, col);
        dfs(board, row-1, col);
        dfs(board, row, col+1);
        dfs(board, row, col-1);
    }

    void bfs(BOARDTYPE &board, int row, int col) {
        if (board[row][col] != 'O') return;
        int N = board.size(), M = board[0].size();
        queue<pair<int, int>> q;
        q.push(make_pair(row, col));
        while (!q.empty())
        {
            int i = q.front().first, j = q.front().second;
            q.pop();
            if (i < 0 || i >= N || j < 0 || j >= M) continue;
            if (board[i][j] != 'O') continue;// important to recheck!
            board[i][j] = 'V';
            q.push(make_pair(i-1, j));
            q.push(make_pair(i+1, j));
            q.push(make_pair(i, j-1));
            q.push(make_pair(i, j+1));
        }
    }
};

No comments:

Post a Comment