leetcode:Surrounded Regions

Problem:

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

Solution:

因为学过一段时间的《数字图像处理》,所以一看到这个题目就想起来了数图中的边缘检测。于是就顺着这个给走下来了,把背景(在board边界之外的)全部看成'O',检测出来'X'的边缘,然后找出一个'X'围起来的圈中的一个内点,然后根据这个内点把圈内的点全部变成'X',然后就得到了结果。

于是:

  1. 在边界上找出来一个'X'
  2. 根据这个'X',沿着他的8-邻居(就是上、下、左、右、右上、右下、左上、左下相邻的点都是邻居,相对比的有一个4-邻居,就是只有上、下、左、右相邻的点是邻居)走,找出来一个封闭的曲线
  3. 然后找出一个内点
  4. 同样根据这个内点的4-邻居,把圈内的点全部变成'X'
  5. 达到目的

事实上,在第4步找内点的时候,费了很大的劲,因为没法判断一个点是不是内点(从一个点走向无穷远穿过边界的次数),因为这个边界有点奇葩。最后想到了反射,就是在找这个边界的时候,其实是知道他外面一圈的点的,于是就上、下、45度以边界上的点反射,找到一个内点。这个结论到现在还不清楚对不对。最后写出来了程序如下,在程序中的测试例子是可以通过的。

#include <iostream>
#include <vector>
using namespace std;


class Solution
{
public:
    void solve(vector<vector<char> > &board)
    {
        int On=-1;
        pair<int,int> cur=get_firstX(board,On); 

        vector<pair<int,int> > path;
        vector<pair<int,int> > Opath;
        get_boundary(cur.first,cur.second,On,board,path,Opath);

        pair<int,int> inner_point=get_inner_point(board,path,Opath);
        vfill(board,path,inner_point);
    }

    pair<int,int> get_inner_point(vector<vector<char> > &board,vector<pair<int,int> > &path, vector<pair<int,int> > &Opath)
    {
        int Onum=Opath.size();
        int nrows=board.size();
        int ncols=board[0].size();
        for(int i=0;i<Onum;i++)
        {
            pair<int,int> tmp;
            if (board[Opath[i].second-1][Opath[i].first+1]=='X' &&
                board[Opath[i].second][Opath[i].first+1]=='X' &&
                board[Opath[i].second+1][Opath[i].first+1]=='X')
            {
               tmp=make_pair(Opath[i].first+2,Opath[i].second); 
            }
            else if(board[Opath[i].second-1][Opath[i].first-1]=='X' &&
                board[Opath[i].second][Opath[i].first-1]=='X' &&
                board[Opath[i].second+1][Opath[i].first-1]=='X')
            {
                tmp=make_pair(Opath[i].first-2,Opath[i].second);
            }
            else if(board[Opath[i].second-1][Opath[i].first+1]=='X' &&
                board[Opath[i].second-1][Opath[i].first]=='X' &&
                board[Opath[i].second-1][Opath[i].first-1]=='X')
            {
                tmp=make_pair(Opath[i].first,Opath[i].second-2);
            }
            else if(board[Opath[i].second+1][Opath[i].first+1]=='X' &&
                board[Opath[i].second+1][Opath[i].first]=='X' &&
                board[Opath[i].second+1][Opath[i].first-1]=='X')
            {
                tmp=make_pair(Opath[i].first,Opath[i].second+2);
            }
            else if(board[Opath[i].second+1][Opath[i].first]=='X' &&
                board[Opath[i].second][Opath[i].first+1]=='X')
            {
                tmp=make_pair(Opath[i].first+1,Opath[i].second+1);
            }
            else if(board[Opath[i].second-1][Opath[i].first]=='X' &&
                board[Opath[i].second][Opath[i].first+1]=='X')
            {
                tmp=make_pair(Opath[i].first-1,Opath[i].second-1);
            }
            else if(board[Opath[i].second+1][Opath[i].first]=='X' &&
                board[Opath[i].second][Opath[i].first-1]=='X')
            {
                tmp=make_pair(Opath[i].first-1,Opath[i].second+1);
            }
            else if(board[Opath[i].second-1][Opath[i].first]=='X' &&
                board[Opath[i].second][Opath[i].first-1]=='X')
            {
                tmp=make_pair(Opath[i].first-1,Opath[i].second-1);
            }
            else
                continue;

            if (tmp.first<ncols-1 && tmp.first>0 && tmp.second<nrows-1 && tmp.second>0 && !on_path(tmp.first,tmp.second,path))
            {
                return tmp;
            }
            else
                continue;
        }


    }
    pair<int,int> get_firstX(vector<vector<char> > &board,int &On)
    {
        //find the first X
        int nrows=board.size();
        int ncols=board[0].size();

        for (int i=0;i<nrows;i++)
            for(int j=0;j<ncols;j++)
            {
                if (i==0 || i==nrows-1 || j==0 || j==ncols-1)
                    if (board[i][j]=='X')
                    {
                        if (i==0) On=2;
                        if (j==0) On=4;
                        if (i==nrows-1) On=0;
                        if (j==ncols-1) On=6;
                        return make_pair(i,j);
                    }
            }
        return make_pair(-1,-1);
    }

    int get_boundary(int seedx,int seedy,int Orin,vector<vector<char> > &board,
                    vector<pair<int,int> > &path,vector<pair<int,int> > &Opath)
    {
        int testx=seedx,testy=seedy;
        int curx=seedx,cury=seedy;
        int On;
        do
        {
            int testn=(Orin+1)%8;
            while(testn%8!=Orin)
            {
                pair<int,int> tmp=get_by_direction(curx,cury,testn);
                testx=tmp.first;
                testy=tmp.second;
                On=((testn/2)*2+6)%8;
                
                int testc=get_color(testx,testy,board);
                if (testc==0)
                {
                    testn=(++testn)%8;
                    Opath.push_back(make_pair(testx,testy));
                }
                else if(testc==1)
                {
                    path.push_back(make_pair(curx,cury));
                    curx=testx;
                    cury=testy;
                    Orin=On;
                    break;
                }
            }
            if (testn%8==Orin)
            {
                //isolated X
                board[curx][cury]='O';
            }
        }while (curx!=seedx || cury!=seedy);

        return 0;
    }

    pair<int,int> get_by_direction(int curx,int cury,int direction)
    {
        int testx,testy;
        switch(direction)
        {
            case 0:
                testx=curx+1;
                testy=cury;
                break;
            case 1:
                testx=curx+1;
                testy=cury-1;
                break;
            case 2:
                testx=curx;
                testy=cury-1;
                break;
            case 3:
                testx=curx-1;
                testy=cury-1;
                break;
            case 4:
                testx=curx-1;
                testy=cury;
                break;
            case 5:
                testx=curx-1;
                testy=cury+1;
                break;
            case 6:
                testx=curx;
                testy=cury+1;
                break;
            case 7:
                testx=curx+1;
                testy=cury+1;
                break;
        }
        return make_pair(testx,testy);
    }

    int get_color(int x,int y,vector<vector<char> > &board)
    {
        //regard the background as 'O'
        int maxx=board[0].size();
        int maxy=board.size();
        if (x>=maxx || x<0)
            return 0;
        if (y>=maxy || y<0)
            return 0;
        return char2int(board[y][x]);
    }
   
    int char2int(char x)
    {
        int res=0;
        switch(x)
        {
            case 'X':
                res=1;
                break;
            case 'O':
                res=0;
                break;
            default:
                res=0;
        }

        return res;
    }

    void vfill(vector<vector<char> > &board,vector<pair<int,int> > &path,pair<int,int> inner_point)
    {
        vector<pair<int,int> > Opoint;
        pair<int,int> cur=inner_point;
        Opoint.push_back(inner_point);
        do
        {   
            cur.first=Opoint.back().first;
            cur.second=Opoint.back().second;
            board[cur.second][cur.first]='Y';
            Opoint.pop_back();
            
            for(int d=0;d<8;d+=2)
            {
                pair<int,int> tmp=get_by_direction(cur.first,cur.second,d);
                if (!on_path(tmp.first,tmp.second,path) && board[tmp.second][tmp.first]!='Y')
                {
                    Opoint.push_back(tmp);
                }
            }
        } while(Opoint.size()!=0);

        int nrows=board.size();
        int ncols=board[0].size();
        for(int i=0;i<nrows;i++)
        {
            for(int j=0;j<ncols;j++)
            {
                if (board[i][j]=='Y')
                {
                    board[i][j]='X';
                }
            }
        }
    }

    bool on_path(int x,int y, vector<pair<int,int> > &path)
    {
        int num=path.size();
        for(int i=0;i<num;i++)
        {
            if (path[i].first== x && path[i].second==y)
                return true;
        }
        return false;
    }
};

int main()
{
    char bd[][4]={{'X','X','X','X'},{'X','O','O','X'},{'X','X','O','X'},{'X','O','X','X'}};
    vector<vector<char> > board(4,vector<char>(4));
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            board[i][j]=bd[i][j];
    Solution s;
    s.solve(board);
    return 0;
}

可是在leetcode上测试的时候,发现总是runtime error,感觉很无力,于是就懒得调试了。到网上看了看别人的代码,原来这么简单,主要的点都在我上面的代码上体现了,就是现在边界上找到一个'O',然后把沿着这个'O'的4-邻居,把它以及与它相连的所有的'O'变成另外一个字母(随便怎么选),然后把剩下的'O'都变成'X',然后把前面的'O'再变回来了,然后结束。


网上的代码的遍历邻居不少是使用的递归实现的,我上面(vfill)的相当于是使用了一个栈。下面是重新整理的代码:


class Solution {
public:
    void solve(vector<vector<char>> &board) {
        if (board.size()==0) return;
        if (board[0].size()==0) return;
        pair<int,int> cur=get_firstO(board); 

        while(cur.first!=-1 || cur.second!=-1)
        {
            flip_openO(board,cur,'Y');
            cur=get_firstO(board);
        }
        flip_from_to(board,'O','X');
        flip_from_to(board,'Y','O');
    }

    pair<int,int> get_firstO(vector<vector<char> > &board)
    {
        //find the first X
        int nrows=board.size();
        int ncols=board[0].size();

        for (int i=0;i<nrows;i++)
            for(int j=0;j<ncols;j++)
            {
                if (i==0 || i==nrows-1 || j==0 || j==ncols-1)
                    if (board[i][j]=='O')
                    {
                        return make_pair(j,i);
                    }
            }
        return make_pair(-1,-1);
    }

    void flip_openO(vector<vector<char> > &board,pair<int,int> &start,char to)
    {
        vector<pair<int,int> > Opoint;
        Opoint.push_back(start);
        pair<int,int> cur=start;
        int nrows=board.size();
        int ncols=board[0].size();
        do
        {   
            cur.first=Opoint.back().first;
            cur.second=Opoint.back().second;
            board[cur.second][cur.first]=to;
            Opoint.pop_back();
            
            for(int d=0;d<8;d+=2)
            {
                pair<int,int> tmp=get_by_direction(cur.first,cur.second,d);
                if (tmp.first>=0 && tmp.first<ncols &&
                    tmp.second>=0 && tmp.second<nrows)
                {
                    if (board[tmp.second][tmp.first]=='O')
                    {
                        Opoint.push_back(tmp);
                    }
                }
            }
        } while(Opoint.size()!=0);
    }

    void flip_from_to(vector<vector<char> > &board,char from, char to)
    {
        int nrows=board.size();
        int ncols=board[0].size();
        for(int i=0;i<nrows;i++)
        {
            for(int j=0;j<ncols;j++)
            {
                if (board[i][j]==from)
                    board[i][j]=to;
            }
        }
    }

    pair<int,int> get_by_direction(int curx,int cury,int direction)
    {
        int testx,testy;
        switch(direction)
        {
            case 0:
                testx=curx+1;
                testy=cury;
                break;
            case 1:
                testx=curx+1;
                testy=cury-1;
                break;
            case 2:
                testx=curx;
                testy=cury-1;
                break;
            case 3:
                testx=curx-1;
                testy=cury-1;
                break;
            case 4:
                testx=curx-1;
                testy=cury;
                break;
            case 5:
                testx=curx-1;
                testy=cury+1;
                break;
            case 6:
                testx=curx;
                testy=cury+1;
                break;
            case 7:
                testx=curx+1;
                testy=cury+1;
                break;
        }
        return make_pair(testx,testy);
    }
};

在leetcode上测试,全部通过。微笑

其实在上面写自己的代码的时候,学长看到了说我怎么写这么多。现在看来果然是掉坑里了。艾,碰到问题还是不要想那么复杂为好~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值