【四十二】【算法分析与设计】flood fill(3),529. 扫雷游戏,LCR 130. 衣橱整理

目录

529. 扫雷游戏

LCR 130. 衣橱整理

结尾


 

529. 扫雷游戏

让我们一起来玩扫雷游戏!

给你一个大小为 m x n 二维字符矩阵 board ,表示扫雷游戏的盘面,其中:

  • 'M' 代表一个 未挖出的 地雷,

  • 'E' 代表一个 未挖出的 空方块,

  • 'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的 已挖出的 空白方块,

  • 数字'1''8')表示有多少地雷与这块 已挖出的 方块相邻,

  • 'X' 则表示一个 已挖出的 地雷。

给你一个整数数组 click ,其中 click = [click(r), click(c)] 表示在所有 未挖出的 方块('M' 或者 'E')中的下一个点击位置(click(r) 是行下标,click(c) 是列下标)。

根据以下规则,返回相应位置被点击后对应的盘面:

  1. 如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'

  2. 如果一个 没有相邻地雷 的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的 未挖出 方块都应该被递归地揭露。

  3. 如果一个 至少与一个地雷相邻 的空方块('E')被挖出,修改它为数字('1''8' ),表示相邻地雷的数量。

  4. 如果在此次点击中,若无更多方块可被揭露,则返回盘面。

示例 1:

输入:board = [["E","E","E","E","E"],["E","E","M","E","E"],["E","E","E","E","E"],["E","E","E","E","E"]], click = [3,0] 输出:[["B","1","E","1","B"],["B","1","M","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]]

示例 2:

输入:board = [["B","1","E","1","B"],["B","1","M","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]], click = [1,2] 输出:[["B","1","E","1","B"],["B","1","X","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]]

提示:

  • m == board.length

  • n == board[i].length

  • 1 <= m, n <= 50

  • board[i][j]'M''E''B' 或数字 '1''8' 中的一个

  • click.length == 2

  • 0 <= click(r) < m

  • 0 <= click(c) < n

  • board[click(r)][click(c)]'M''E'

 
class Solution {
public:
    int row, col;
    vector<vector<char>> updateBoard(vector<vector<char>>& board,
                                     vector<int>& click) {
        row = board.size(), col = board[0].size();
        int x = click[0], y = click[1];
        dfs(board, x, y);
        return board;
    }
    int dx[8] = {1, -1, 0, 0, 1, 1, -1, -1},
        dy[8] = {0, 0, 1, -1, 1, -1, 1, -1};
    void dfs(vector<vector<char>>& board, int i, int j) {
        // 当前
        if (board[i][j] == 'M') {
            board[i][j] = 'X';
            return;
        }
        int count = 0;
        for (int k = 0; k < 8; k++) {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < row && y >= 0 && y < col && board[x][y] == 'M') {
                count++;
            }
        }
        if (count == 0) {
            board[i][j] = 'B';
            for (int k = 0; k < 8; k++) {
                int x = i + dx[k], y = j + dy[k];
                if (x >= 0 && x < row && y >= 0 && y < col &&
                    board[x][y] == 'E') {
                    dfs(board, x, y);
                }
            }
        } else {
            board[i][j] = count + '0';
            return;
        }
    }
};

class Solution {

public:

int row, col;

这里定义了两个成员变量rowcol,用于存储棋盘的行数和列数。

vector<vector<char>> updateBoard(vector<vector<char>>& board,

vector<int>& click) {

row = board.size(), col = board[0].size();

updateBoard函数接收当前棋盘状态board和玩家点击的位置click,然后更新rowcol为棋盘的行列数。

int x = click[0], y = click[1];

dfs(board, x, y);

return board;

}

提取出玩家点击的行x和列y,调用dfs函数进行深度优先搜索来更新棋盘,最后返回更新后的棋盘。

int dx[8] = {1, -1, 0, 0, 1, 1, -1, -1},

dy[8] = {0, 0, 1, -1, 1, -1, 1, -1};

定义两个数组dxdy,用于表示一个格子周围8个方向的偏移量。

void dfs(vector<vector<char>>& board, int i, int j) {

dfs函数用于深度优先搜索,参数ij表示当前搜索到的格子位置。

if (board[i][j] == 'M') {

board[i][j] = 'X';

return;

}

如果当前格子是雷('M'),就把它标记为被挖出的雷('X'),然后返回。

int count = 0;

for (int k = 0; k < 8; k++) {

int x = i + dx[k], y = j + dy[k];

if (x >= 0 && x < row && y >= 0 && y < col && board[x][y] == 'M') {

count++;

}

}

计算当前格子周围的雷数。通过循环检查8个方向,如果存在雷('M'),则count加一。

if (count == 0) {

board[i][j] = 'B';

for (int k = 0; k < 8; k++) {

int x = i + dx[k], y = j + dy[k];

if (x >= 0 && x < row && y >= 0 && y < col &&

board[x][y] == 'E') {

dfs(board, x, y);

}

}

} else {

board[i][j] = count + '0';

return;

}

}

};

如果周围雷数为0,则将当前格子标记为'B'(表示周围没有雷),并对周围的每个'E'(未被揭示的空格)进行递归搜索。如果周围雷数不为0,则将当前格子标记为相应的数字(雷数),显示周围有多少雷,然后返回。

LCR 130. 衣橱整理

家居整理师将待整理衣橱划分为 m x n 的二维矩阵 grid,其中 grid[i][j] 代表一个需要整理的格子。整理师自 grid[0][0] 开始 逐行逐列 地整理每个格子。

整理规则为:在整理过程中,可以选择 向右移动一格 向下移动一格,但不能移动到衣柜之外。同时,不需要整理 digit(i) + digit(j) > cnt 的格子,其中 digit(x) 表示数字 x 的各数位之和。

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

示例 1:

输入:m = 4, n = 7, cnt = 5 输出:18

提示:

  • 1 <= n, m <= 100

  • 0 <= cnt <= 20

 
class Solution {
public:
    int ret;
    int row, col;
    int cnt;
    vector<vector<bool>> visit;
    int wardrobeFinishing(int m, int n, int _cnt) {
        cnt = _cnt;
        row = m, col = n;
        visit = vector<vector<bool>>(row, vector<bool>(col));

        dfs(0, 0);
        return ret;
    }
    int dx[2] = {0, 1}, dy[2] = {1, 0};

    void dfs(int i, int j) {
        // 当前
        if (check(i, j)) {
            ret++;
        }
        visit[i][j] = true;

        for (int k = 0; k < 2; k++) {
            int x = i + dx[k], y = j + dy[k];
            if (x >= 0 && x < row && y >= 0 && y < col && !visit[x][y] &&
                check(x, y)) {
                dfs(x, y);
            }
        }
    }

    bool check(int i, int j) {
        int tmp = 0;
        while (i) {
            tmp += i % 10;
            i /= 10;
        }
        while (j) {
            tmp += j % 10;
            j /= 10;
        }
        return tmp <= cnt;
    }
};

class Solution {

public:

int ret; // 定义一个变量ret,用于记录符合条件的点的数量

int row, col; // 定义两个变量row和col,分别存储给定区域的行数和列数

int cnt; // 定义一个变量cnt,用于存储题目中给定的数值,与“check”函数中的计算相关

vector<vector<bool>> visit; // 定义一个二维bool向量visit,用于标记某个位置是否被访问过

int wardrobeFinishing(int m, int n, int _cnt) {

cnt = _cnt; // 初始化cnt为给定的_cnt

row = m, col = n; // 初始化行数row和列数col

visit = vector<vector<bool>>(row, vector<bool>(col)); // 初始化visit矩阵,大小为m*n dfs(0, 0); // 从坐标(0,0)开始深度优先搜索

return ret; // 返回符合条件的点的总数

}

int dx[2] = {0, 1}, dy[2] = {1, 0}; // 定义两个数组dx和dy,表示可以向右和向下移动 void dfs(int i, int j) {

// 当前

if (check(i, j)) { // 如果当前点(i,j)的坐标和满足条件

ret++; // 符合条件的点的数量加一

}

visit[i][j] = true; // 标记当前点(i,j)已被访问

for (int k = 0; k < 2; k++) { // 遍历可以移动的两个方向

int x = i + dx[k], y = j + dy[k]; // 计算移动后的新坐标(x,y)

if (x >= 0 && x < row && y >= 0 && y < col && !visit[x][y] &&

check(x, y)) { // 如果新坐标有效、未被访问过、且满足条件

dfs(x, y); // 对新坐标进行深度优先搜索

}

}

}

bool check(int i, int j) {

int tmp = 0; // 用于计算当前坐标数字之和的临时变量

while (i) { // 循环直到i为0

tmp += i % 10; // 将i的个位数加到tmp上

i /= 10; // i除以10,去掉个位数

}

while (j) { // 循环直到j为0

tmp += j % 10; // 将j的个位数加到tmp上

j /= 10; // j除以10,去掉个位数 }

return tmp <= cnt; // 如果tmp小于等于cnt,则返回true,否则返回false

}

};

这段代码的核心功能是通过深度优先搜索(DFS),遍历给定区域内所有可能的点,利用check函数判断每个点的行坐标和列坐标的数字之和是否不超过给定的值cnt。如果满足条件,ret增加1,最终返回所有满足条件的点的数量。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妖精七七_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值