我爱学算法之——floodfill算法(下)

五、太平洋大西洋水流问题

题目解析

给定一个二维数组 heights、其中 heights[i][j] 表示该单元格的高度;

当 附近相邻单元格的高度,小于等于当前单元格高度时,当前单元格雨水可以流向附近单元格;(雨水可以从边缘单元格流向海洋)

要我们找出 既可以流向太平洋(左、上部分)、又可以流向大西洋(右、下部分)的单元格。

算法思路

简单来说这道题就是 要找出 即与左、上部分相连,又与右、下部分相连的所有单元格。

要直接去遍历,判断每一个单元格是否可以流向左上、右下部分;那实在太麻烦了;

这里我们就可以从边缘单元格开始遍历,记录每一个连通(可以流向边缘)的单元格,最后找出及可以流向左上部分、又可以流向右下部分的单元格即可。

代码实现

cpp 复制代码
class Solution {
    int dx[4] = {-1,1,0,0};
    int dy[4] = {0,0,-1,1};
public:
    void dfs(vector<vector<int>>& heights, int i, int j,vector<vector<bool>>& vis)
    {
        vis[i][j] = true;
        int m = heights.size();
        int n = heights[0].size();
        for(int k =0; k<4;k++)
        {
            int x = i + dx[k];
            int y = j + dy[k];
            if(x>=0 &&x<m && y>=0 && y<n && !vis[x][y] && heights[i][j] <= heights[x][y])
                dfs(heights,x,y,vis);
        }
    }
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
        int m = heights.size();
        int n = heights[0].size();
        vector<vector<bool>> pac(m,vector<bool>(n,false));
        vector<vector<bool>> atl(m,vector<bool>(n,false));
        // 上 下
        for(int i = 0;i<n;i++)
        {
            if(!pac[0][i])  dfs(heights,0,i,pac);
            if(!atl[m-1][i])   dfs(heights,m-1,i,atl);
        }
        // 左 右
        for(int i = 0;i<m;i++)
        {
            if(!pac[i][0])  dfs(heights,i,0,pac);
            if(!atl[i][n-1]) dfs(heights,i,n-1,atl);
        }
        vector<vector<int>> ret;
        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;
    }
};

六、扫雷游戏

题目解析

扫雷游戏,作为一个经典的小游戏,具体规则这里就就不详细叙述了;看这道题的要求

给一个 m*n 的棋盘;M代表 为挖出的雷、E代表未挖出的方块、B代表相邻位置没有雷的已挖出的方块、数字1-8表示该位置附近雷的个数、X代表已经挖出的地雷。

给定一个位置[click[0],click[1]],返回该位置被点击后对应的盘面。

具体规则

  • 地雷 M 被挖出,游戏结束,把它修改成 X
  • 该位置是附近没有地雷的空方块 E,修改它为B,并将与其相邻的所有未挖出的方块都递归揭露(修改成B,或者1-8
  • 如果该位置至少与一个地雷相邻,则修改为数字 1-8
  • 如果该位置已经被揭露,则直接返回

算法思路

读懂了这道题,仔细分析一下,其实并不是很难;

只要从 [click[0],click[1]]位置 进行依次 DFS 遍历,判断附近是否存在地雷、揭露相邻的空方格即可。

  • 判断该位置是否是地雷或者是否已经被揭露
  • 判断该位置附近是否存在地雷,地雷的个数;如果该位置与地雷相邻,将该位置修改成地雷的个数,返回即可
  • 依次揭露附近的空方格

代码实现

cpp 复制代码
class Solution {
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

    int getNearM(vector<vector<char>>& board, int x, int y) {
        int ret = 0;
        int m = board.size(), n = board[0].size();
        for (int i = 0; i < 8; i++) {
            int posx = x + dx[i];
            int posy = y + dy[i];
            if (posx >= 0 && posx < m && posy >= 0 && posy < n &&
                (board[posx][posy] == 'M' || board[posx][posy] == 'X'))
                ret++;
        }
        return ret;
    }
    void dfs(vector<vector<char>>& board, int x, int y) {
        if (board[x][y] == 'M') {
            board[x][y] = 'X';
            return;
        }
        int num = getNearM(board, x, y);
        if (num > 0) {
            board[x][y] = '0' + num;
            return;
        }
        board[x][y] = 'B';
        int m = board.size(), n = board[0].size();
        for (int i = 0; i < 8; i++) {
            int posx = x + dx[i];
            int posy = y + dy[i];
            if (posx >= 0 && posx < m && posy >= 0 && posy < n &&
                board[posx][posy] == 'E')
                dfs(board, posx, posy);
        }
    }

public:
    vector<vector<char>> updateBoard(vector<vector<char>>& board,
                                     vector<int>& click) {
        dfs(board, click[0], click[1]);
        return board;
    }
};

七、衣橱整理

题目解析

有一个 m*n 的二维矩阵,g[i][j]表示一个需要整理的格子,现在要从 g[0][0]开始逐行逐列的整理每一个格子。

在整理过程中,可以向下或者向右移动一格;

digit(i) + digit(j) > cnt时,表示g[i][j]这个格子不需要整理(digit(x)表示数 x 的各位数之和)

要返回 : 总共需要整理多少个格子

算法思路

这道题虽然只给了数字 m、n以及 cnt,但构想出一个二维数组,从[0,0]位置进行一次 DFS 遍历即可。

DFS 遍历:

  • 判断当前位置是否需要整理(如果不需要直接返回)
  • 标记当前位置(已经遍历过),统计结果
  • 遍历当前位置 右、下两个方向(没有遍历过,再进行 DFS 遍历)。

代码实现

cpp 复制代码
class Solution {
    int dx[2] = {0, 1};
    int dy[2] = {1, 0};
    int result = 0;
    bool vis[110][110];
public:
    int digit(int x) {
        int ret = 0;
        while (x) {
            ret += (x % 10);
            x /= 10;
        }
        return ret;
    }
    void dfs(int m, int n, int x, int y, int cnt) {
        if (digit(x) + digit(y) > cnt)
            return;
        result++;
        vis[x][y] = true;
        for (int i = 0; i < 2; i++) {
            int posx = x + dx[i];
            int posy = y + dy[i];
            if (posx < m && posy < n && !vis[posx][posy])
                dfs(m, n, posx, posy, cnt);
        }
    }
    int wardrobeFinishing(int m, int n, int cnt) {
        int ret = 0;
        dfs(m, n, 0, 0, cnt);
        return result;
    }
};
sy])
                dfs(m, n, posx, posy, cnt);
        }
    }
    int wardrobeFinishing(int m, int n, int cnt) {
        int ret = 0;
        dfs(m, n, 0, 0, cnt);
        return result;
    }
};

本篇文章主要分享三道经典DFS类题目的思路与代码实现,供刷题参考

相关推荐
2401_851272992 小时前
编译器内建函数使用
开发语言·c++·算法
Rhystt2 小时前
代码随想录算法训练营第五十五天|图论理论基础、深搜理论基础、98. 所有可达路径、广搜理论基础
数据结构·c++·算法·深度优先·图论
Book思议-2 小时前
【数据结构实战】C 语言实现静态顺序队列:从原理到完整可运行代码
c语言·数据结构·算法·队列
hanlin032 小时前
刷题笔记:力扣第6题-Z字形变换
笔记·算法·leetcode
努力学习的小廉2 小时前
我爱学算法之——记忆化搜索
算法
for_ever_love__2 小时前
Objective-C学习: OC方法调用的本质
开发语言·学习·ios·objective-c
m0_730115112 小时前
C++与Python混合编程实战
开发语言·c++·算法
前端小趴菜~时倾3 小时前
自我提升-python爬虫学习:day04
爬虫·python·学习
郝学胜-神的一滴4 小时前
Leetcode 969 煎饼排序✨:翻转间的数组排序艺术
数据结构·c++·算法·leetcode·面试