LeetCode刷题专题:FloodFill泛滥填充算法剖析

题目1:图像渲染(LeetCode 733)

  1. 题目描述

提示:

  • m == image.length
  • n == image[i].length
  • 1 <= m, n <= 50
  • 0 <= image[i][j], color < 216
  • 0 <= sr < m
  • 0 <= sc < n
  1. 核心算法思路

本题是经典Flood Fill洪水填充算法,二选一即可实现:深度优先搜索 DFS(递归写法,本题代码采用);广度优先搜索 BFS(队列迭代写法)

通用逻辑:遍历当前像素上下左右4个方向所有相连、且原始像素值相同的点,批量修改颜色,遍历完所有连通区域即完成渲染。

递归DFS函数设计

1) 函数参数

a. 原始二维图像矩阵:待修改的图片数组

b. 当前遍历坐标 (i,j):正在处理的像素位置

c. 目标修改颜色 newColor:最终要替换成的像素值

额外全局记录:原始初始像素颜色 prev(防止修改后颜色错乱,重复递归)

2) 递归函数体执行流程

  1. 先把当前位置像素,直接改成目标颜色(前置判断保证:所有进入递归的坐标,一定是需要修改的合法点)

  2. 遍历当前点上下左右4个方向的相邻坐标

  3. 合法性判断:坐标不越界(在矩阵行数、列数范围内);像素原始颜色 = 初始点颜色

  4. 满足条件 → 递归深入处理该相邻像素

cpp 复制代码
class Solution
{
    // 上下左右 4个方向偏移量,x行偏移,y列偏移
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};

    int m, n;       // 矩阵行数、列数
    int prev;       // 记录起点原始像素颜色,避免递归死循环

public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color)
    {
        // 特殊情况:起点颜色本来就是目标颜色,无需修改,直接返回原图
        if(image[sr][sc] == color) return image;

        m = image.size();           // 获取矩阵总行数
        n = image[0].size();         // 获取矩阵总列数
        prev = image[sr][sc];       // 保存起点原本的像素值

        dfs(image, sr, sc, color); // 递归深度优先遍历渲染

        return image;
    }

    // DFS递归核心函数
    void dfs(vector<vector<int>>& image, int i, int j, int color)
    {
        image[i][j] = color; // 第一步:直接修改当前像素颜色

        // 遍历4个方向
        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 && image[x][y] == prev)
            {
                dfs(image, x, y, color);
            }
        }
    }
};
  1. 核心知识点&易错重点总结

1) 四连通规则

本题只认上下左右4个方向,斜对角像素不属于连通区域,这是和八连通填充的核心区别。

2) 为什么要提前保存原始颜色prev?

如果不保存原始颜色,直接修改当前像素后,后续递归判断image[x][y] == 原颜色会失效,同时会出现无限递归死循环。

3) 递归终止隐含逻辑

坐标超出矩阵边界,自动停止递归;像素颜色不等于原始颜色,不进入递归;天然实现DFS遍历结束,无需额外写return终止语句。

4) 复杂度分析

时间复杂度:O(m×n),最坏情况整张图片所有像素都需要遍历修改

空间复杂度:O(m×n),最坏递归深度等于整张图片像素数量

5) 同类拓展

Flood Fill算法广泛用于:图像抠图、区域染色、迷宫寻路、岛屿数量统计、连通块计数题目


题目2:岛屿数量(LeetCode 200)

  1. 题目描述

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0''1'
  1. 核心算法思路

本题是Flood Fill洪水填充算法的经典应用,和「733.图像渲染」是同一系列的连通块问题。

通用逻辑

遍历整个矩阵,每次遇到一块未访问的陆地:

1) 说明找到一个新岛屿,将岛屿数量 ret +1

2) 用DFS/BFS将这块岛屿的所有连通陆地标记为「已访问」(或直接修改为水)

3) 遍历完成后,ret 就是岛屿总数

DFS 算法流程

1) 初始化岛屿数量 ret = 0

2) 双重循环遍历二维网格的每个格子:

若当前格子是未访问的陆地(grid[i][j] == '1' 且未被访问):

ret++(岛屿数量+1)

调用DFS,将该岛屿的所有连通陆地标记为已访问

3) 遍历完成后返回 ret

递归DFS函数设计

核心步骤:标记当前格子为已访问;向上下左右4个方向递归寻找相邻陆地,满足以下条件才进入递归:坐标不越界,格子未被访问,格子值为 '1'(陆地)

cpp 复制代码
class Solution
{
    vector<vector<bool>> vis; // 标记已访问的格子
    int m, n;                 // 矩阵行数、列数

public:
    int numIslands(vector<vector<char>>& grid)
    {
        m = grid.size();
        if (m == 0) return 0;
        n = grid[0].size();
        vis = vector<vector<bool>>(m, vector<bool>(n));

        int ret = 0; // 岛屿数量
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                // 遇到未访问的陆地,开始填充
                if (!vis[i][j] && grid[i][j] == '1')
                {
                    ret++;
                    dfs(grid, i, j);
                }
            }
        }
        return ret;
    }

    // 上下左右四个方向的偏移量
    int dx[4] = {0, 0, -1, 1};
    int dy[4] = {1, -1, 0, 0};

    void dfs(vector<vector<char>>& grid, int i, int j)
    {
        vis[i][j] = true; // 标记为已访问
        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] && grid[x][y] == '1')
            {
                dfs(grid, x, y);
            }
        }
    }
};
  1. 关键知识点&易错点

1) 核心思想:标记访问避免重复统计

每次遇到未访问的陆地,就把整个连通块标记为已访问,这样后续遍历就不会重复统计同一个岛屿。

写法1:用额外的 vis 数组标记(代码中使用的方式,不修改原数据)

写法2:直接把访问过的陆地改为 '0'(节省空间,修改原数据)

2) 四连通规则

岛屿的连通性只看上下左右四个方向,斜对角不算连通,和「图像渲染」的连通规则一致。

3) 复杂度分析

时间复杂度:O(m×n),每个格子最多被访问一次

空间复杂度:O(m×n),最坏情况(全是陆地)递归深度为矩阵大小

4) 与「图像渲染」的关系

本题的DFS逻辑和「733.图像渲染」几乎完全一致:图像渲染:把所有连通的同色格子改成目标色;岛屿数量:把所有连通的陆地格子标记为已访问,统计连通块数量;本质都是Flood Fill 洪水填充算法的应用。

  1. 拓展:BFS解法思路(队列实现)

如果担心DFS递归深度过大导致栈溢出,可以用BFS队列实现:

1) 遇到陆地时,将坐标加入队列

2) 不断取出队首元素,标记为已访问,并将其四个方向的合法陆地加入队列

3) 队列为空时,当前岛屿的所有陆地已被标记完成


题目3:岛屿的最大面积(LeetCode 695)

  1. 题目描述
  1. 核心算法思路

本题依然是 Flood Fill 洪水填充算法 的经典应用,和「200.岛屿数量」是同一系列的连通块问题。

通用逻辑

  1. 遍历整个矩阵,每次遇到一块未访问的陆地(grid[i][j] == 1)

  2. 用 DFS/BFS 计算该岛屿的面积(连通块内所有 1 的数量)

  3. 维护一个全局变量,记录所有岛屿面积中的最大值

  4. 遍历完成后,返回最大值(没有岛屿则为 0)

主函数流程

  1. 初始化最大面积 ret = 0

  2. 双重循环遍历矩阵每个格子:若当前格子是未访问的陆地,调用 DFS 计算该岛屿的面积;将计算出的面积与 ret 比较,更新 ret 为较大值

  3. 遍历完成后返回 ret

DFS递归函数流程

  1. 标记当前格子为已访问

  2. 初始化面积计数 count += 1(当前格子面积为1)

  3. 向上下左右四个方向递归:若相邻格子合法、未访问且为陆地,则递归处理,并累加面积

  4. 递归结束后,count 即为当前岛屿的总面积

cpp 复制代码
class Solution
{
    bool vis[51][51];   // 标记已访问的格子
    int m, n;           // 矩阵行数、列数
    int dx[4] = {0, 0, 1, -1}; // 上下左右四个方向偏移量
    int dy[4] = {1, -1, 0, 0};
    int count;          // 记录当前岛屿的面积

public:
    int maxAreaOfIsland(vector<vector<int>>& grid)
    {
        m = grid.size();
        n = grid[0].size();
        int ret = 0;

        // 遍历整个矩阵
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                // 遇到未访问的陆地,开始计算岛屿面积
                if (!vis[i][j] && grid[i][j] == 1)
                {
                    count = 0; // 重置当前岛屿面积
                    dfs(grid, i, j);
                    ret = max(ret, count); // 更新最大面积
                }
            }
        }
        return ret;
    }

    void dfs(vector<vector<int>>& grid, int i, int j)
    {
        count++;                // 当前格子面积+1
        vis[i][j] = true;       // 标记为已访问

        // 遍历四个方向
        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] && grid[x][y] == 1)
            {
                dfs(grid, x, y);
            }
        }
    }
};
  1. 关键知识点&易错点
  1. 与「岛屿数量」的核心区别

岛屿数量:只需要统计连通块的个数

岛屿的最大面积:不仅要统计连通块,还要计算每个连通块的大小,并记录最大值

  1. 两种标记访问的方式

方式1:额外开辟 vis 数组(代码中使用的方式,不修改原数据,更安全)

方式2:直接将访问过的 1 修改为 0(节省空间,但会修改原矩阵)

  1. 复杂度分析

时间复杂度:O(m×n),每个格子最多被访问一次

空间复杂度:O(m×n),最坏情况(全是陆地)递归深度为矩阵大小

  1. 易错点提醒

必须注意四连通规则:斜对角的 1 不算连通,示例1中答案不是11,就是因为斜对角的陆地不属于同一个岛屿

每次遇到新岛屿时,要重置面积计数变量 count,避免不同岛屿的面积互相干扰


题目4:被围绕的区域(LeetCode 130)

  1. 题目描述
  1. 核心思路:正难则反

直接找"被包围的区域"比较困难,我们反过来思考:

  1. 标记安全区域:从矩阵的四条边界出发,用 DFS 遍历所有与边界相连的 'O',将它们临时标记为 '.'(表示这些 'O' 是安全的,不会被填充)。

  2. 填充被包围区域:遍历整个矩阵:

遇到 'O':说明它没有被标记,是被包围的区域,直接改为 'X'。

遇到 '.':说明它是安全区域,恢复为 'O'。

|--------|-------------------------------------------------------------------------|
| 细节 | 说明 |
| 越界检查 | DFS中必须先判断 x >= 0 && x < m && y >= 0 && y < n,否则会访问矩阵外的内存导致崩溃。 |
| 临时标记 | 用.标记安全的O,避免重复遍历;如果直接修改为X,会丢失边界O的信息。 |
| 边界遍历 | 四条边界都要遍历,不能遗漏任何一条,否则会漏掉部分安全O。 |
| 递归终止条件 | DFS遇到非O(X或.)时就停止,避免无限递归。 |

  1. 完整 C++ 代码
cpp 复制代码
class Solution
{
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    int m, n;

public:
    void solve(vector<vector<char>>& board)
    {
        m = board.size(), n = board[0].size();

        // 1. 把边界的 O 相连的联通块,全部修改成 .
        for(int j = 0; j < n; j++)
        {
            if(board[0][j] == 'O') dfs(board, 0, j);
            if(board[m - 1][j] == 'O') dfs(board, m - 1, j);
        }
        for(int i = 0; i < m; i++)
        {
            if(board[i][0] == 'O') dfs(board, i, 0);
            if(board[i][n - 1] == 'O') dfs(board, i, n - 1);
        }

        // 2. 还原
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(board[i][j] == '.') board[i][j] = 'O';
                else if(board[i][j] == 'O') board[i][j] = 'X';
            }
        }
    }

    void dfs(vector<vector<char>>& board, int i, int j)
    {
        board[i][j] = '.';
        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 && board[x][y] == 'O')
            {
                dfs(board, x, y);
            }
        }
    }
};

题目5:太平洋大西洋水流问题(LeetCode 417)

  1. 题目描述
  1. 核心思路:反向 DFS

直接判断"能否流向两个海洋"会重复遍历大量路径,效率低下。我们反向思考:

  1. 反向标记可达太平洋的单元格:从太平洋沿岸(上、左边界)出发,反向 DFS(允许从低到高或等高流动),标记所有能反向流到太平洋的单元格。

  2. 反向标记可达大西洋的单元格:从大西洋沿岸(下、右边界)出发,反向 DFS,标记所有能反向流到大西洋的单元格。

  3. 求交集:同时被两个标记矩阵标记的单元格,就是既能流向太平洋、又能流向大西洋的结果。

cpp 复制代码
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>>& h)
    {
        m = h.size(), n = h[0].size();
        vector<vector<bool>> pac(m, vector<bool>(n));
        vector<vector<bool>> atl(m, vector<bool>(n));

        // 1. 先处理 pac 洋
        for(int j = 0; j < n; j++) dfs(h, 0, j, pac);
        for(int i = 0; i < m; i++) dfs(h, i, 0, pac);

        // 2. 处理 atl 洋
        for(int i = 0; i < m; i++) dfs(h, i, n - 1, atl);
        for(int j = 0; j < n; j++) dfs(h, m - 1, j, 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;
    }

    void dfs(vector<vector<int>>& h, int i, int j, vector<vector<bool>>& vis)
    {
        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] && h[x][y] >= h[i][j])
                dfs(h, x, y, vis);
        }
    }
};
  1. 核心知识点总结
  1. 正难则反思想

两道题都用了反向遍历的技巧:

被围绕的区域:不直接找被包围的 'O',而是先标记安全的 'O'。

水流问题:不直接找能流向海洋的单元格,而是从海洋反向找能到达的单元格。

这种方法避免了重复遍历和复杂的路径判断,大幅提升了效率。

  1. DFS 通用模板

两道题的 DFS 逻辑高度相似,可总结为以下模板:

cpp 复制代码
// 四个方向偏移量
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

void dfs(矩阵/数组, 当前位置, 标记矩阵/临时状态) {
    // 1. 边界/终止条件判断
    if (越界 || 已访问 || 不满足条件) return;
    
    // 2. 标记当前状态(已访问/临时修改)
    标记当前位置为已访问/安全;
    
    // 3. 递归遍历四个方向
    for (int k = 0; k < 4; k++) {
        int x = i + dx[k];
        int y = j + dy[k];
        dfs(矩阵/数组, x, y, 标记矩阵/临时状态);
    }
}
  1. 矩阵遍历的边界处理

遍历边界时,注意区分四条边:上边界(i=0)、下边界(i=m-1)、左边界(j=0)、右边界(j=n-1)。

反向 DFS 时,要注意流动条件的反转(如水流问题中,从"从高到低"变为"从低到高/等高")。


题目6:扫雷游戏(LeetCode 529)

  1. 题目描述

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 50
  • board[i][j]'M''E''B' 或数字 '1''8' 中的一个
  • click.length == 2
  • 0 <= clickr < m
  • 0 <= clickc < n
  • board[clickr][clickc]'M''E'
  1. 解法

算法思路:模拟类型的DFS题目。首先要搞懂题目要求(游戏规则),从题目所给的点击位置开始,根据游戏规则,来一次DFS即可。

1)先搞懂题目要我们做什么

我们要模拟扫雷游戏里"点击一下棋盘"后的变化。棋盘上有几种格子:

M:没挖开的地雷

E:没挖开的空白格子

B:已经挖开、周围没有地雷的空白格子

数字1-8:已经挖开、周围有对应数量地雷的格子

X:被挖开的地雷(游戏结束)

我们的任务,就是根据点击的位置,按照游戏规则更新整个棋盘的状态。

2)分情况处理点击的位置

情况1:直接点到了地雷(M)

这是最简单的情况:游戏直接结束。

只需要把这个格子改成X,然后直接返回更新后的棋盘就行,其他格子都不用动。

情况2:点到了空白格子(E)

这是最复杂的情况,我们需要分两步处理:

第一步:数清楚这个格子周围有多少个地雷

我们要检查这个格子的8个相邻方向(上下左右+4个对角线),数出里面有多少个M。

这一步是判断接下来要做什么的关键。

第二步:根据地雷数量,执行不同的规则

  1. 如果周围有地雷(数量 ≥ 1)

这个格子不能继续扩展,只能显示地雷的数量。

我们把这个格子改成对应的数字字符(比如周围有2个雷,就改成'2'),然后就不用再处理其他格子了。

  1. 如果周围没有地雷(数量 = 0)

这个格子要被标记为B,并且触发"连锁展开"效果:所有和它连通的、没挖开的空白格子(E)都要被自动挖开。

怎么做连锁展开?我们就对这个格子的8个相邻方向,逐个检查:

如果相邻的格子是E,就对它重复上面的"数雷-判断-处理"流程(也就是递归处理)。

如果相邻的格子已经被挖开(B、数字)或者是地雷(M),就跳过,不用管它。

3)整个流程的核心逻辑

你可以把整个过程理解成:

  1. 先判断点击的是不是地雷,是就直接结束。

  2. 如果是空白格子,先数它周围的地雷数量。

  3. 有雷就改成数字,结束;没雷就改成B,然后把周围所有能连通的空白格子都按同样的规则处理一遍。

  4. 一直重复,直到所有能挖开的格子都被处理完,返回最终的棋盘状态。

C++ 算法代码

cpp 复制代码
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);
                }
            }
        }
    }
};

题目7:衣橱整理(LeetCode LCR 130)/ 机器人的运动范围

  1. 题目描述

地上有一个 m 行 n 列的方格,从坐标 [0,0] 到坐标 [m-1,n-1]。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于 k 的格子。

例如:当 k 为18时,机器人能够进入方格 [35,37],因为 3+5+3+7=18。但它不能进入方格 [35,38],因为 3+5+3+8=19。请问该机器人能够到达多少个格子?

示例1

输入:m = 2, n = 3, k = 1 输出:3

示例2

输入:m = 3, n = 1, k = 0 输出:1

提示

• 1 <= n, m <= 100

• 0 <= k <= 20

  1. 算法思路

这是一道非常典型的「搜索」类问题。我们可以通过「深搜(DFS)」或者「宽搜(BFS)」,从 [0, 0] 点出发,按照题目的「规则」一直往 [m - 1, n - 1] 位置走。

同时,设置一个全局变量,每次走到一个合法位置,就将全局变量加一。当我们把所有能走到的路都走完之后,全局变量里面存的就是最终答案。

  1. 解法(DFS)

递归函数设计

a. 参数:当前所在的位置 [i, j],行走的边界 [m, n],坐标数位之和的边界 k

b. 递归出口:

i. [i, j] 的坐标不合法(超出能走的范围)

ii. [i, j] 位置已经走过了(需要创建一个全局变量 bool st[101][101],标记当前位置是否走过)

iii. [i, j] 坐标的数位之和大于 k

上述情况的任何一种都是递归出口

c. 函数体内部:

i. 如果这个坐标是合法的,就将全局变量 ret++

ii. 标记 [i, j] 位置已经遍历过

iii. 向 [i, j] 位置的上下左右四个方向继续搜索

辅助函数

a. 检测坐标 [i, j] 是否合法

b. 计算出 i, j 的数位之和,然后与 k 作比较

主函数

a. 调用递归函数,从 [0, 0] 点出发

辅助的全局变量

a. 二维数组 bool st[101][101]:标记 [i, j] 位置是否已经遍历过

b. 变量 ret:记录一共到达多少个合法的位置

c. 上下左右的四个坐标变换

这道题是 LCR 130. 衣橱整理,本质就是「机器人的运动范围」,只是换了个"整理衣橱"的场景:衣橱被划分为 m 行 n 列的格子;整理师从 (0,0) 出发,只能向右/向下移动;不能移动到衣柜外,也不能整理坐标数位和大于 cnt 的格子;求能整理的格子总数

解题思路:和之前的机器人运动范围思路完全一致,用DFS/BFS搜索即可

核心逻辑

  1. 数位和计算:先写一个辅助函数,计算一个数字的各位数字之和(比如 35 → 3+5=8)

  2. DFS 搜索:

从 (0,0) 出发,每次尝试向右/向下走一步

每走到一个格子,先判断是否合法(没越界、没走过、数位和≤cnt)

合法就计数+1,标记为已访问,再递归搜索下一个格子

  1. 边界剪枝:越界、已访问、数位和超标的格子直接跳过,不继续递归
cpp 复制代码
class Solution {
public:
    // 记录是否访问过
    bool vis[101][101] = {false};
    int m, n, cnt;
    int res = 0;
    // 方向:向右、向下
    int dx[2] = {1, 0};
    int dy[2] = {0, 1};

    // 计算数字的数位和
    int digitSum(int x) {
        int sum = 0;
        while(x) {
            sum += x % 10;
            x /= 10;
        }
        return sum;
    }

    void dfs(int i, int j) {
        // 越界判断
        if(i < 0 || i >= m || j < 0 || j >= n) return;
        // 已访问过
        if(vis[i][j]) return;
        // 数位和超过限制
        if(digitSum(i) + digitSum(j) > cnt) return;

        // 标记已访问,计数+1
        vis[i][j] = true;
        res++;

        // 向右、向下递归
        for(int k = 0; k < 2; k++) {
            int x = i + dx[k];
            int y = j + dy[k];
            dfs(x, y);
        }
    }

    int wardrobeFinishing(int m, int n, int cnt) {
        this->m = m;
        this->n = n;
        this->cnt = cnt;
        dfs(0, 0);
        return res;
    }
};
相关推荐
笨蛋不要掉眼泪1 小时前
Java并发编程:深入剖析 ArrayBlockingQueue
java·开发语言·算法·并发
菜菜的顾清寒1 小时前
力扣HOT100(33)二叉树的最大深度
算法·leetcode·职场和发展
Deepoch1 小时前
Deepoc数学大模型:重塑半导体研发与制造的核心算法范式
人工智能·算法·机器学习·半导体·deepoc·数学大模型
一支黑色の铅笔1 小时前
MongoDB Aggregation Pipeline 常用 Stage 速查
数据库·算法·mongodb
Bingorl1 小时前
机器学习之决策树算法
算法·决策树·机器学习
qingyulee2 小时前
线性回归、决策树
人工智能·算法·线性回归
Zhang~Ling2 小时前
C++ 继承机制详解下:多继承、虚继承与菱形继承底层原理
开发语言·c++·算法
西安邮电大学2 小时前
2026华为OD机考真题附答案-计算数列位置N的值
java·算法
AI算法沐枫2 小时前
机器学习经典小项目4:泰坦尼克号生存预测
人工智能·python·深度学习·线性代数·算法·机器学习·回归