Leetcode|Surrounded Regions

本文探讨了一种二维棋盘中捕获被‘X’包围的‘O’区域的问题,通过深度优先搜索(DFS)和广度优先搜索(BFS)两种算法实现,详细介绍了递归与非递归的实现方式,并对比了不同实现的时间效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

这道题体现了基本的搜索算法,体现了经典的深度优先算法和广度优先算法。
深度优先算法:
我刚开始的思路是单独设立一个矩阵来标记是否走过,以及是区分出不同的O的集合区,以便遍历之后可以确定是否为转换区。结果超时!
现附上一种Runtime error的DFS算法:

void search(vector<vector<char>>& board,vector<vector<char>>& visit,int r,int c,bool& success,int count){
        if(r<0||r>=board.size()||c<0||c>=board[0].size()){
            success=true;
            return;//success 'O' is valid
        } 
        if(board[r][c]=='X'||visit[r][c]!='0') return;//go on searching
        visit[r][c]=count+'0';
        search(board,visit,r+1,c,success,count);
        search(board,visit,r-1,c,success,count);
        search(board,visit,r,c+1,success,count);
        search(board,visit,r,c-1,success,count);
    }

    void solve(vector<vector<char>>& board) {
        if(board.size()==0) return;
        map<int,int> cc;
        int count=0;//record Nth search 
        vector<vector<char>> visit(board.size(),vector<char>(board[0].size(),'0'));
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if(board[i][j]=='X'||visit[i][j]!='0') continue;
                ++count;
                bool success=false;
                search(board,visit,i,j,success,count);
                if(!success) cc[count]=count;
            }
        }
        for(int r=0;r<board.size();r++){
             for(int c=0;c<board[0].size();c++){
                    if(board[r][c]=='X'||cc.find(visit[r][c])==cc.end()) continue;
                          board[r][c]='X';
                     }
                }

    }

其实这种思路麻烦了,首先没有必要设立一个标记矩阵visit。换个思路想一下,什么情况是不用转换的呢,那么就是至少有一个O是在边上的。这里我们先从边上开始搜索,找出边界为O的格子,然后顺着这个格子进行DFS搜索。将和该格子联通的O全变为另一个字符(例如V);
最后再将O(需要转换的区域)变为X,将V变为O;

这种思路如果仍然采用递归,就是比上面的少设定了一个矩阵,节省了O(N)的空间。时间上其实没什么改变。
代码仍然超时!

    void dfs(int row, int col,vector<vector<char> >& board)
    {
        if(row < 0 || row >= board.size() || col < 0 || col >= board[0].size()) return;
        if(board[row][col] != 'O') return;
        board[row][col] = 'V';
        dfs(row - 1, col, board);//up
        dfs(row, col + 1, board);//right
        dfs(row + 1, col, board);//down
        dfs(row, col - 1, board);//left
    }
    void solve(vector<vector<char> > &board)
    {
        if(board.size() == 0 || board[0].size() == 0)
            return;
         int rows = board.size();
         int cols = board[0].size();
         for(int i = 0; i < rows; ++i){
             dfs(i, 0, board);
             dfs(i, cols - 1, board);
         }
         for (int j = 0; j < cols; ++j)
         {
             dfs(0, j, board);
             dfs(rows - 1, j, board);
         }
         for(int i = 0; i < rows; ++i)
             for (int j = 0; j < cols; ++j)
             {
                if(board[i][j] == 'O')
                    board[i][j] = 'X';
                else if(board[i][j] == 'V')
                     board[i][j] = 'O';      
             }   
    }

既然递归超时,那么采用非递归形式的DFS。(20ms)

struct cordinate{
        int row,col;
        void set(int r,int c){
            row=r;
            col=c;
        }
        cordinate(int r,int c):row(r),col(c){}
    };
    void solve(vector<vector<char>>& board) {
        if(board.size()==0||board[0].size()==0) return;
        int row=board.size();
        int col=board[0].size();
        queue<cordinate> q;
        cordinate point(0,0);
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(board[i][j]=='O'&&(i==0||i==row-1||j==0||j==col-1))   DFS(board,i,j);
            }
        }
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(board[i][j]=='O') board[i][j]='X';
                else if(board[i][j]=='V') board[i][j]='O';
            }
        }

    }

    void DFS(vector<vector<char>>& board,int i,int j){
        int row=board.size();
        int col=board[0].size();
        stack<cordinate> q;
        cordinate point(i,j);
        board[i][j]='V';
        q.push(point);
        while(!q.empty()){
            point=q.top();
            int r=point.row;
            int c=point.col;
            if(r<row-1&&board[r+1][c]=='O'){//right
                board[r+1][c]='V';
                point.set(r+1,c);
                q.push(point);
                continue;
            }
            if(c>0&&board[r][c-1]=='O'){//down
                board[r][c-1]='V';
                point.set(r,c-1);
                q.push(point);
                continue;
            }
            if(r>0&&board[r-1][c]=='O'){//left
                board[r-1][c]='V';
                point.set(r-1,c);
                q.push(point);
                continue;
            }
            if(c<col-1&&board[r][c+1]=='O'){//up
                board[r][c+1]='V';
                point.set(r,c+1);
                q.push(point);
                continue;
            }
            q.pop();
        }
    }

道理差不多,再写一个BFS的。(16ms)比DFS速度略快。

struct cordinate{
        int row,col;
        void set(int r,int c){
            row=r;
            col=c;
        }
        cordinate(int r,int c):row(r),col(c){}
    };
    void solve(vector<vector<char>>& board) {
        if(board.size()==0||board[0].size()==0) return;
        int row=board.size();
        int col=board[0].size();
        queue<cordinate> q;
        cordinate point(0,0);
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(board[i][j]=='O'&&(i==0||i==row-1||j==0||j==col-1))   DFS(board,i,j);
            }
        }
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(board[i][j]=='O') board[i][j]='X';
                else if(board[i][j]=='V') board[i][j]='O';
            }
        }

    }

    void DFS(vector<vector<char>>& board,int i,int j){
        int row=board.size();
        int col=board[0].size();
        stack<cordinate> q;
        cordinate point(i,j);
        board[i][j]='V';
        q.push(point);
        while(!q.empty()){
            point=q.top();
            int r=point.row;
            int c=point.col;
            if(r<row-1&&board[r+1][c]=='O'){//right
                board[r+1][c]='V';
                point.set(r+1,c);
                q.push(point);
                continue;
            }
            if(c>0&&board[r][c-1]=='O'){//down
                board[r][c-1]='V';
                point.set(r,c-1);
                q.push(point);
                continue;
            }
            if(r>0&&board[r-1][c]=='O'){//left
                board[r-1][c]='V';
                point.set(r-1,c);
                q.push(point);
                continue;
            }
            if(c<col-1&&board[r][c+1]=='O'){//up
                board[r][c+1]='V';
                point.set(r,c+1);
                q.push(point);
                continue;
            }
            q.pop();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值