zoukankan      html  css  js  c++  java
  • [LeetCode] 130. Surrounded Regions 包围区域

     1.DFS  

           这道题让将矩阵中被'X'包围的不接触边框的'O组成的连通分量用'X'替换,显然可以使用DFS的方法解答,直接的想法是,遍历二维矩阵,遇到‘O’使用DFS判断由'O'组成的连通分量有没有接触到边框,

    没有接触到DFS返回true,并将'O组成的连通分量用'X'替换;否则返回false,不替换。在使用DFS遍历'O'连通分量的过程中使用数组保存遍历路径。此种方法容易出错。代码如下:

    /*
     * @Descripttion: 
     * @version: 
     * @Author: wangxf
     * @Date: 2020-04-14 20:38:54
     * @LastEditors: Do not edit
     * @LastEditTime: 2020-04-20 23:19:05
     */
    /*
     * @lc app=leetcode.cn id=130 lang=cpp
     *
     * [130] 被围绕的区域
     */
    
    // @lc code=start
    #include<bits/stdc++.h>
    using namespace std;
    class Solution {
    public:
        void solve(vector<vector<char>>& board) {
             if(board.empty()||board.size()<1) return;
             vector<vector<char>> flag =  board;
             raw_len = board.size();
             col_len = board[0].size();
             for(int i = 0;i<raw_len;++i)
                for(int j = 0;j<col_len;++j)
                {
                    flag[i][j]='N';//未访问
                }
             for(int i = 0;i<raw_len;++i)
                for(int j = 0;j<col_len;++j)
                {
                    if(board[i][j]=='O'){
                        vector<pair<int,int> > pathVec;
                        pathVec.clear();
                        bool isModify = dfs(board,flag,pathVec,i,j);
                        if(isModify)
                        {
                            vector<pair<int,int> >::iterator ite = pathVec.begin();
                            for(;ite!=pathVec.end();++ite){
                                int x = ite->first;
                                int y = ite->second;
                                board[x][y]='X';
                            }
                        }
                    }
                }
            return;
        }
        bool dfs(vector<vector<char> >& board,vector<vector<char> >& flag,
                 vector<pair<int,int> >& pathVec,int i,int j)
        {
             if(!(i>=0&&i<raw_len&&j>=0&&j<col_len)){//放在函数最开始,避免数组下标越界
                 return false;
             } 
             bool status = true;
             if(board[i][j]=='O'&&flag[i][j]=='N'){//没有被访问过的‘O’节点
                flag[i][j]='Y';//标记访问
                pair<int,int> point = make_pair(i,j);
                pathVec.push_back(point);//记录一次dfs过程中的路径
                if(i==0||j==0){//遇到边界,不填充
                    status=false;
                }
                int dx[4]={0,0,-1,1};
                int dy[4]={1,-1,0,0};
                for(int k=0;k<4;++k){
                    status=(status&dfs(board,flag,pathVec,i+dx[k],j+dy[k]));
                }
                return status;
             }
            return status; 
        }
    private:
        int raw_len;
        int col_len;
    };
    // @lc code=end

         另一种比较巧妙一点的DFS方法是扫矩阵的四条边,如果有O,则用 DFS 遍历,将所有连着的O都变成另一个字符,比如 $,这样剩下的O都是被包围的,然后将这些O变成X,把$变回O就行了。代码如下:

    class Solution {
    public:
        void solve(vector<vector<char> >& board) {
            for (int i = 0; i < board.size(); ++i) {
                for (int j = 0; j < board[i].size(); ++j) {
                    if ((i == 0 || i == board.size() - 1 || j == 0 || j == board[i].size() - 1) && board[i][j] == 'O')
                        solveDFS(board, i, j);
                }
            }
            for (int i = 0; i < board.size(); ++i) {
                for (int j = 0; j < board[i].size(); ++j) {
                    if (board[i][j] == 'O') board[i][j] = 'X';
                    if (board[i][j] == '$') board[i][j] = 'O';
                }
            }
        }
        void solveDFS(vector<vector<char> > &board, int i, int j) {
            if (board[i][j] == 'O') {
                board[i][j] = '$';
                if (i > 0 && board[i - 1][j] == 'O') 
                    solveDFS(board, i - 1, j);
                if (j < board[i].size() - 1 && board[i][j + 1] == 'O') 
                    solveDFS(board, i, j + 1);
                if (i < board.size() - 1 && board[i + 1][j] == 'O') 
                    solveDFS(board, i + 1, j);
                if (j > 0 && board[i][j - 1] == 'O') 
                    solveDFS(board, i, j - 1);
            }
        }
    };

    2.并查集

    /*
     * @Descripttion: 
     * @version: 
     * @Author: wangxf
     * @Date: 2020-04-14 20:38:54
     * @LastEditors: Do not edit
     * @LastEditTime: 2020-05-07 23:29:17
     */
    /*
     * @lc app=leetcode.cn id=130 lang=cpp
     *
     * [130] 被围绕的区域
     */
    
    // @lc code=start
    #include<bits/stdc++.h>
    using namespace std;
    class UF
    {
    private:
        int count;//连通的个数
        vector<int> parent;//保存节点的父节点
        vector<int> size;//保存节点所在连通分量的重量(节点数)
    public:
        // 构造函数初始化
        UF(int n)
        {
            count = n;
            parent.resize(n);
            size.resize(n);
            for(int i = 0; i < n; i++)
            {
                parent[i] =i;
                size[i] = 1;
            }
        }
        // 将节点p 和 节点 q 连通
        void Union(int p, int q)
        {
            int rootP = find(p);
            int rootQ = find(q);
            if(rootP == rootQ)
                return;
            
            if(size[rootP] > size[rootQ])
            {
                parent[rootQ] = rootP;
                size[rootP] += size[rootQ];
            }
            else
            {
                parent[rootP] = rootQ;
                size[rootQ] += size[rootP];
            }
            count--;//连通个数 -1
        }
        //判断节点p 和 节点 q 是否连通
        bool connected(int p, int q)
        {
            int rootP = find(p);
            int rootQ = find(q);
            return rootP==rootQ;
        }
        //返回当前连通个数
        int count_num()
        {
            return count;
        }
    private:
        // 寻找 x 节点的根节点
        int find(int x)
        {
            while(parent[x] != x)
            {
                //查找根节点的同时,对树进行路径压缩,
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }
    };
    
    //并查集常见思路是:适当增加虚拟节点,想办法让元素「分门别类」,建立动态连通关系。
    class Solution {
    public:
        void solve(vector<vector<char>>& board)
        {
            if(board.empty()||board.size()==0) return;
            const int m = board.size();
            const int n = board[0].size();
            UF *uf = new UF(m*n+1);//给dummy节点留一个位置
            int dummy = m*n; 
            //将首列和末列的‘O’和dummy连通
            for(int i = 0;i<m;++i)
            {
                if(board[i][0]=='O') uf->Union(n*i+0,dummy);
                if(board[i][n-1]=='O') uf->Union(n*i+n-1,dummy);
            }
            //将首行和末行的‘O’和dummy连通
            for (size_t j = 0; j < n; j++)
            {
                if(board[0][j]=='O') uf->Union(n*0+j,dummy);
                if(board[m-1][j]=='O') uf->Union(n*(m-1)+j,dummy);
            }
            int dx[]={1,-1,0,0};
            int dy[]={0,0,1,-1};
            for(int i = 1;i<m-1;++i)
               for(int j= 1;j<n-1;++j){
                   if(board[i][j]=='O')
                   {
                      for(int k = 0;k<4;++k)//这里不用考虑越界问题
                      {
                          int x =i+dx[k];
                          int y =j+dy[k];
                          if (board[x][y] == 'O')
                             uf->Union(i*n+j,x*n+y);
                      }
                   }
               }
            for(int i = 1;i<m-1;++i)
               for(int j= 1;j<n-1;++j)
            {
                        
                   if(!uf->connected(i*n+j,dummy))//和dummy连通的点一定和边界的点连通
                   {
                       board[i][j]='X';
                   }
            }
            return;
        }
    };
    // @lc code=end

      

  • 相关阅读:
    JSP页面间传递参数
    JSP获取当前日期时间
    jsp实现套打(发票打印)
    iframe
    HTTP状态码及含义大全
    标签 -- HTML内联框架
    jstl fmt标签详解
    button和submit的区别及使用js实现页面跳转的方式
    Idea SpringBoot 启动Eurka 报错,提示端口被占用
    CodeSmith 破解
  • 原文地址:https://www.cnblogs.com/wangxf2019/p/12741549.html
Copyright © 2011-2022 走看看