FloodFill 算法 (下)

目录

太平洋大西洋水流问题

题解:

扫雷游戏

题解:

衣橱整理


太平洋大西洋水流问题

417. 太平洋大西洋水流问题 - 力扣(LeetCode)

题解:

如果从区域内某一个位置出发,需要向左、向上走判断是否能到达太平洋,向右、向下走判断是否能到达大西洋,同时能到达太平洋和大西洋的位置,便是我们想要的答案,如果二维矩阵的每一个点都这样判断,时间复杂度很高,我们可以换个方向思考。

假设矩阵中的某一点存在一条路径可以到达太平洋,那么从这一点出发,这条路径中的相邻点的高度是单调递减的(非严格),相反,如果从太平洋出发,这条路径中的相邻点的高度是单调递增的(非严格),到达大西洋的路径也是同理。

那么我们可以从太平洋出发,找一条递增的路径,从大西洋出发,找一条递增的路径,如果这两条路径相交于同一点,那么这个点既可以流向太平洋,也可以流向大西洋。

于是问题转换为建立一个名为 pac 的 bool 类型的二维数组,从太平洋的边界(即第一行、第一列)出发,找出所有的递增路径,并把路径中的每个点标记为 true,大西洋也是同理,二维数组命名为 alt 。寻找递增路径的代码便为 FloodFill 算法。

之后再去遍历二维矩阵 heights:

1、如果 heights[ i ][ j ] 的 pac[ i ][ j ] 和 alt[ i ][ j ] 都为 true,则该点同时可以流向太平洋和大西洋,是我们想要的答案;

2、如果 heights[ i ][ j ] 的 pac[ i ][ j ] 和 alt[ i ][ j ] 有一个为 false,则该点无法同时流向太平洋和大西洋!

class Solution {
    int m,n;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
public:
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
        m=heights.size(),n=heights[0].size();
        vector<vector<bool>> pac(m,vector<bool>(n));
        vector<vector<bool>> atl(m,vector<bool>(n));
        vector<vector<int>> ret;
        for(int i=0;i<n;i++) 
        {
            dfs(heights,pac,0,i);//第一行
            dfs(heights,atl,m-1,i);//最后一行
        }
        for(int i=0;i<m;i++) 
        {
            dfs(heights,pac,i,0);//第一列
            dfs(heights,atl,i,n-1);//最后一列
        }
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(pac[i][j] && atl[i][j]) ret.push_back({i,j});
            }
        }
        return ret;
    }
    void dfs(vector<vector<int>>& heights,vector<vector<bool>>& vis,int i,int j)
    {
        vis[i][j]=true;
        for(int k=0;k<4;k++)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && heights[x][y]>=heights[i][j])
            {
                dfs(heights,vis,x,y);
            }
        }
    }
};

扫雷游戏

529. 扫雷游戏 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/minesweeper/description/

题解:

 这道题相当于给了一个点源:

1、如果该点是未挖出的雷(M),那么把这个雷标记为已挖出(X),并且直接返回盘面;

2、如果该点是未挖出的空方格(E),则把周围方格都递归的揭露:

a.如果方格周围 8 个方格都没有雷,则把该方格标记为 B,且继续递归,继续揭露;

b.如果方格周围 8 个方格存在雷,则标记出雷的个数,且不再递归。

 需要注意由于需要访问周围 8 个方格,所以 dx、dy 也需要根据偏移量设置为大小为 8 的数组。

class Solution {
    int dx[8]={0,0,1,-1,-1,-1,1,1};
    int dy[8]={1,-1,0,0,-1,1,-1,1};
    int m,n;
public:
    vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
        m=board.size(),n=board[0].size();
        int x=click[0],y=click[1];
        //踩雷
        if(board[x][y]=='M')
        {
            board[x][y]='X';
            return board;
        }
        dfs(board,x,y);
        return board;
    }
    void dfs(vector<vector<char>>& board, int i,int j)
    {
        //判断当前位置周围有没有地雷
        int count=0;
        for(int k=0;k<8;k++)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && board[x][y]=='M')  ++count;
        }
        //有地雷
        if(count)
        {
            board[i][j]=count+'0';
            return;
        }
        else//没有地雷
        {
            board[i][j]='B';
            for(int k=0;k<8;k++)
            {
                int x=i+dx[k],y=j+dy[k];
                if(x>=0 && x<m && y>=0 && y<n && board[x][y]=='E') 
                {
                    dfs(board,x,y);//没有地雷的地方继续向外扩展
                }
            }
        }
    }
};

衣橱整理

LCR 130. 衣橱整理 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/description/

 这道题只需要向下和向右扩展。

lass Solution {
    int dx[2]={0,1};
    int dy[2]={1,0};
    
    bool vis[101][101];
public:
    int wardrobeFinishing(int m, int n, int cnt) {
        
        int ret=0;
        dfs(m,n,0,0,cnt,ret);
        return ret;
    }
    void dfs(int m, int n,int i,int j,int cnt,int& ret)
    {
        vis[i][j]=true;
        ++ret;
        for(int k=0;k<2;k++)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && check(x,y,cnt))
                dfs(m,n,x,y,cnt,ret);
        }
    }
    bool check(int i,int j,int cnt)
    {
        int tmp=0;
        while(i)
        {
            tmp+=(i%10);
            i/=10;
        }
        while(j)
        {
            tmp+=(j%10);
            j/=10;
        }
        if(tmp>cnt) return false;
        else return true;
    }
    
};

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值