面试高频题 力扣 LCR 130.衣柜整理 洪水灌溉(FloodFill) 深度优先遍历(dfs) 暴力搜索 C++解题思路 每日一题

目录

  • 零、题目描述
  • 一、为什么这道题值得一看?
  • 二、题目拆解:核心要素与约束
  • 三、算法实现:基于 DFS 的解决方案
    • 代码逻辑拆解
  • 五、时间复杂度与空间复杂度
    • 时间复杂度
    • 空间复杂度
  • 六、坑点总结
  • 七、举一反三
  • 八、洪水灌溉(Flood Fill)系列问题总结

零、题目描述

题目链接: LCR 130.衣橱整理(注:LCR 130 与剑指 Offer 13 相同)

在这里插入图片描述

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

示例 2
输入:m = 2, n = 3, cnt = 1
输出:3
解释:
满足条件的格子坐标为 (0,0)、(0,1)、(1,0)。

  • (0,0):数位和 0+0=0 ≤ 1
  • (0,1):数位和 0+1=1 ≤ 1
  • (1,0):数位和 1+0=1 ≤ 1
  • (0,2):数位和 0+2=2 > 1(不满足)
  • (1,1):数位和 1+1=2 > 1(不满足)
  • (1,2):数位和 1+2=3 > 1(不满足)

一、为什么这道题值得一看?

这道题是网格搜索问题的经典变种,核心围绕“带条件的路径探索”展开,能帮你深化对深度优先搜索(DFS)在约束场景下的应用理解。

它的独特价值在于:

  1. 固定起点的探索:不同于需要遍历多个起点的问题,本题仅从 (0,0) 出发,更聚焦于“单起点扩散”的逻辑;
  2. 有限移动方向:只能向右或向下移动,需要针对性设计搜索路径,避免无效探索;
  3. 自定义过滤条件:通过数位和判断是否访问格子,增加了搜索过程中的“筛选”环节,考验条件整合能力。

通过本题,你能掌握:

  • 如何在 DFS 中嵌入自定义判断条件(如数位和计算);
  • 如何处理网格中的边界与访问标记;
  • 单起点、有限方向场景下的搜索逻辑设计。

对DFS(深度优先搜索)和洪水灌溉算法感兴趣的朋友,不妨看看我的每日一题专栏。专栏里,在本篇之前的内容已经围绕这两个主题做了层层铺垫——从基础的递归逻辑、网格遍历,到洪水灌溉的核心思想,每一步都有细致的拆解和代码解析。

而今天这篇,更像是对“洪水灌溉”系列问题的一次总结收尾。因此,代码层面不会再做过于细致的逐行讲解(那些细节在前几篇中已有充分覆盖),重点会放在思路的梳理和这类问题的共性规律上,帮你形成完整的解题框架~

二、题目拆解:核心要素与约束

核心目标
统计从 (0,0) 出发,通过向右或向下移动可到达的、且满足 digit(x) + digit(y) ≤ cnt 的格子总数(包含起点)。

关键要素解析

  1. 数位和计算
    需实现函数 digit(x),计算数字 x 的各数位之和。例如:x=12 时,1+2=3x=0 时,结果为 0。

  2. 移动规则
    每次移动只能选择两个方向:

    • 向右:(x, y) → (x, y+1)
    • 向下:(x, y) → (x+1, y)
  3. 访问条件
    一个格子 (x, y) 可被访问,需同时满足:

    • 坐标在网格内:0 ≤ x < m0 ≤ y < n
    • 未被访问过(避免重复计数);
    • 数位和满足:digit(x) + digit(y) ≤ cnt
  4. 计数逻辑
    每访问一个满足条件的格子,就将计数器加 1,最终返回计数器的值。

三、算法实现:基于 DFS 的解决方案

完整代码

class Solution {
public:// 方向数组:向右(0,1)、向下(1,0)int dx[2] = {0, 1};int dy[2] = {1, 0};// 标记已访问的格子,避免重复计数bool visited[100][100] = {false};// 计数变量:记录满足条件的格子总数int count = 0;// 网格大小与数位和阈值(全局变量,避免参数传递冗余)int m, n, cnt;int wardrobeFinishing(int _m, int _n, int _cnt) {m = _m;n = _n;cnt = _cnt;// 先检查起点是否满足条件if (digit(0) + digit(0) > cnt) {return 0;}// 标记起点为已访问,启动DFSvisited[0][0] = true;dfs(0, 0);return count;}// DFS:从(x,y)出发,探索所有可达的有效格子void dfs(int x, int y) {// 访问当前格子,计数+1count++;// 尝试两个方向的移动for (int i = 0; i < 2; i++) {int nx = x + dx[i];  // 新行坐标int ny = y + dy[i];  // 新列坐标// 检查新坐标是否满足所有条件if (isValid(nx, ny)) {visited[nx][ny] = true;  // 标记为已访问dfs(nx, ny);             // 递归探索}}}// 辅助函数:判断(nx, ny)是否可访问bool isValid(int nx, int ny) {// 条件1:在网格边界内if (nx < 0 || nx >= m || ny < 0 || ny >= n) {return false;}// 条件2:未被访问过if (visited[nx][ny]) {return false;}// 条件3:数位和满足要求if (digit(nx) + digit(ny) > cnt) {return false;}return true;}// 辅助函数:计算数字x的数位和int digit(int x) {int sum = 0;while (x > 0) {sum += x % 10;  // 累加最后一位x /= 10;        // 移除最后一位}return sum;}
};

代码逻辑拆解

1. 方向数组设计
由于只能向右或向下移动,方向数组定义为:

  • dx[0] = 0, dy[0] = 1 → 向右移动(行不变,列+1)
  • dx[1] = 1, dy[1] = 0 → 向下移动(行+1,列不变)

2. 数位和计算(digit(x))

  • 功能:将数字 x 拆分为各个数位,返回总和。
  • 实现逻辑:通过 x % 10 取最后一位,累加至 sum,再通过 x /= 10 移除最后一位,循环至 x = 0
  • 示例:x=23 时,23%10=3x=22%10=2x=0,总和为 3+2=5

3. 有效性判断(isValid(nx, ny)
整合三大条件的判断,避免在 DFS 中重复写逻辑:

  • 边界检查:确保 (nx, ny) 处于网格内;
  • 访问检查:通过 visited 数组判断是否已访问;
  • 数位和检查:计算 digit(nx) + digit(ny) 并与 cnt 比较。

4. DFS 递归流程

  1. 进入 dfs(x, y) 后,先将当前格子计入总数(count++);
  2. 遍历两个移动方向,计算新坐标 (nx, ny)
  3. 通过 isValid(nx, ny) 检查新坐标是否可访问;
  4. 若可访问,标记为已访问并递归调用 dfs(nx, ny),继续探索。

5. 起点特殊处理
在启动 DFS 前,需先判断起点 (0,0) 的数位和是否满足条件。若不满足(如 cnt < 0),直接返回 0,无需执行 DFS。

五、时间复杂度与空间复杂度

时间复杂度

  • 网格访问:每个格子最多被访问一次,共 m×n 个格子;
  • 数位和计算:对每个坐标 (x,y),数位和计算时间为 O(log x + log y)x 最大为 m-1y 最大为 n-1);
  • 总复杂度O(m×n×(log m + log n)),可简化为 O(m×n)(因 log mlog n 为常数级)。

空间复杂度

  • 递归栈:最坏情况下(所有格子均有效),递归深度为从 (0,0)(m-1,n-1) 的路径长度,即 O(m + n)
  • 访问标记数组visited 为固定大小的 100×100 数组,空间复杂度为 O(1)
  • 总复杂度O(m + n)

六、坑点总结

  1. 数位和计算错误

    • 忽略 x=0 的情况:digit(0) 应返回 0,若循环条件写为 x >= 0 会导致死循环(x=0x%10=0x/10=0,无限循环)。
    • 错误处理负数:题目中 x 为坐标(非负),无需考虑负数,但需确保函数对非负整数有效。
  2. 方向数组设计错误
    误加入向左或向上的方向,导致访问无效格子或重复计数(如 (0,0) 向左移动到 (0,-1) 会越界)。

  3. 未标记已访问
    虽然移动方向固定(右/下),理论上不会重复访问,但特殊场景下(如 m=1, n=1)可能出错,需严格标记访问状态。

  4. 起点判断遗漏
    未提前检查起点是否满足条件,导致 (0,0) 无效时仍启动 DFS,计数错误(如 cnt=-1 时,错误返回 1)。

七、举一反三

掌握本题逻辑后,可尝试解决以下类似问题:

  • LeetCode 62. 不同路径:计算从 (0,0)(m-1,n-1) 的路径总数(无过滤条件,仅统计路径数);
  • LeetCode 63. 不同路径 II:在 62 题基础上增加障碍物,需在搜索中过滤障碍格子;
  • 剑指 Offer 13. 机器人的运动范围:与本题完全一致,仅表述不同。

八、洪水灌溉(Flood Fill)系列问题总结

回顾这几天的5篇博客,从岛屿数量到今天的 衣橱整理,我们围绕洪水灌溉(Flood Fill)算法展开了一系列递进式学习。这些题目虽场景各异,但核心逻辑一脉相承,又在细节上层层深入,共同构成了对网格搜索问题的完整认知。

1.共性:洪水灌溉的核心框架
所有题目都围绕 “连通区域遍历与标记” 展开,共享以下核心逻辑:

  1. 遍历触发:从特定起点(或多个起点)出发,触发深度优先搜索(DFS)或广度优先搜索(BFS);
  2. 方向探索:通过方向数组(4方向、8方向等)遍历相邻单元格,模拟“洪水扩散”;
  3. 访问标记:通过原地修改(如将1改为0)或额外数组标记已访问区域,避免重复处理;
  4. 边界控制:严格检查坐标合法性(是否在网格范围内),防止越界。

2.递进:从基础到进阶的能力拆解

(1) 基础:连通区域的“计数”与“计量”

  • LeetCode 200. 岛屿数量:入门级题目,核心是“统计连通区域数量”。通过4方向DFS遍历,每发现一个未标记的陆地(1)就计数,并“淹没”整个岛屿(标记为0)。这是洪水灌溉的最基础形态,教会我们“如何识别并标记一个完整的连通区域”。
  • LeetCode 695. 岛屿的最大面积:在计数基础上升级为“计量区域规模”。同样用4方向DFS,但新增“面积累加”逻辑(每次访问陆地时累加计数),并跟踪最大值。这一步让我们学会“在遍历中携带并更新数据”。

(2)进阶:思维反转与复杂条件

  • LeetCode 130. 被围绕的区域:引入“反向标记”思维。不再直接寻找“被围绕的区域”,而是从边界出发标记“不被围绕的安全区”(与边缘连通的O),最后通过排除法处理目标区域。这一步打破了“正向搜索”的固定思维,学会“正难则反”的策略。
  • LeetCode 417. 太平洋大西洋水流问题:进一步深化反向思维。通过双标记数组(分别记录能流向两大洋的区域),从海洋边界“逆流”标记可达区域,最终取交集。这题训练了“多目标标记与结果整合”的能力。

(3)拓展:方向与条件的灵活适配

  • LeetCode 529. 扫雷游戏:扩展遍历方向至8方向(含对角线),并新增“条件终止”逻辑(根据周围地雷数决定是否继续扩散)。这题让我们学会“根据场景调整探索范围”和“动态控制递归深度”。
  • LCR 130. 衣橱整理:加入“自定义过滤条件”(数位和判断),且限制移动方向为2方向(右/下)。这题展示了洪水灌溉在“带约束的单起点扩散”场景中的应用,强调“条件过滤与方向限制”的结合。

3.收获:从“会用”到“会变通”
通过这一系列题目,我们不仅掌握了洪水灌溉的基础框架,更理解了“算法复用与变体适配”的核心思维:

  • 不变的是框架:无论场景如何变化,“遍历触发→方向探索→访问标记→边界控制”的流程始终是核心,掌握这一点,就能应对80%的网格搜索问题;
  • 可变的是细节:根据题目目标调整“起点选择”(单起点/多起点/边界起点)、“方向范围”(4方向/8方向/有限方向)、“过滤条件”(无限制/数位和/高度差等)、“目标输出”(计数/计量/标记/交集),就能将基础框架转化为具体问题的解法。

4.总结
洪水灌溉系列问题的本质,是 “如何系统性地探索并处理网格中的连通区域” 。从简单的“数岛屿”到复杂的“带条件的单起点扩散”,我们走过的每一步都是对“遍历逻辑”“标记技巧”“思维角度”的深化。

未来遇到新的网格问题时,不妨先问自己:

  • 起点在哪里?
  • 需要向哪些方向扩散?
  • 如何标记已访问区域?
  • 有哪些过滤条件会影响扩散?

想清楚这四个问题,再结合洪水灌溉的基础框架,就能举一反三,轻松应对各类变体。算法学习的核心,从来不是死记代码,而是掌握“不变的逻辑”,并灵活调整“可变的细节”——这正是这一系列题目带给我们的最大收获。

欢迎在评论区分享你的解题思路或优化方案,一起碰撞思维火花~🌟

在这里插入图片描述

觉得有收获的话,不妨点个赞鼓励一下~顺手关注专栏,后续还有更多算法进阶内容,带你稳步提升不迷路!😉

随着洪水灌溉系列的收尾,接下来我们将进入DFS的记忆化搜索新专题——这是优化递归效率的核心技巧,能帮你解决更多“重复计算”场景的问题。下次咱们要讨论的入门题是力扣 509. 斐波那契数,看似简单的递归背后藏着记忆化的精妙逻辑,感兴趣的朋友可以提前琢磨:如何用缓存避免重复计算?递归与记忆化结合能带来多大的效率提升?蹲一波更新,带你从基础案例吃透记忆化搜索的本质~

这是封面原图~谢谢支持!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89996.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ext4文件系统全景解析

目录Ext4文件系统全景解析&#xff1a;从inode到数据恢复实战1. Ext文件系统的"小区规划"&#xff1a;块组结构详解 &#x1f3d8;️1.1 块组&#xff1a;文件系统的基本管理单元1.2 超级块的"多重备份"机制 &#x1f6e1;️2. inode&#xff1a;文件的&qu…

贪心算法Day4学习心得

先来看第一道&#xff1a;860. 柠檬水找零 - 力扣&#xff08;LeetCode&#xff09; 有如下三种情况&#xff1a; 情况一&#xff1a;账单是5&#xff0c;直接收下。情况二&#xff1a;账单是10&#xff0c;消耗一个5&#xff0c;增加一个10情况三&#xff1a;账单是20&#…

接口自动化测试种涉及到接口依赖怎么办?

《接口自动化测试中接口依赖的处理方式及选择原则》在接口自动化测试中&#xff0c;接口依赖是指某个接口的请求参数、执行条件或测试结果依赖于其他接口的输出&#xff08;如返回数据、状态等&#xff09;。处理接口依赖是确保测试用例准确性和稳定性的关键&#xff0c;常见的…

hive分区表临时加载日批数据文件

源系统每日上传一个csv数据文件到数据中台指定目录&#xff0c;数据中台用hive表进行ETL工作。 先建一个外部分区表&#xff1a; create external table tmp_lease_contract ( contract_id string, vin string, amount float ) partitioned by (dt string) row format delim…

Python关于pandas的基础知识

一.扫盲&#xff08;一&#xff09;、pandas 是什么pandas 是 Python 的一个第三方数据处理库&#xff0c;它提供了高效、灵活的数据结构&#xff08;如 Series 和 DataFrame&#xff09;&#xff0c;能方便地对结构化数据进行清洗、转换、分析和处理。&#xff08;二&#xff…

React 英语单词补全游戏——一个寓教于乐的英语单词记忆游戏

预览&#xff1a;英语单词补全 &#x1f4d6; 产品概述 英语单词大冒险是一款专为 7-12 岁儿童设计的互动式英语学习游戏。通过听音频、补全单词的游戏方式&#xff0c;让孩子在轻松愉快的环境中提升英语词汇能力和听力水平。 &#x1f3af; 核心价值主张 寓教于乐: 将枯燥…

我的第一个开源项目 -- 实时语音识别工具

这是我的第一个开源项目&#xff0c;是我一直想做的一个小工具&#xff1a; 端到端实时语音转文字系统。 通过小程序和H5页面&#xff0c;用户可以实时采录音频&#xff0c;通过ws上传到java的netty server。 Java在经过权限验证、流量控制等操作之后&#xff0c;通过gRPC流…

AG32 mcu+cpld 联合编程(概念及流程)

在使用mcucpld联合编程之前&#xff0c;请确认已经熟练掌握mcu的使用方法&#xff0c;并且对cpld编程&#xff08;verilog语言&#xff09;有一定的基础。 另外&#xff0c;对AHB总线也需要有一定的了解。 这个章节分为两部分&#xff1a; 第一部分&#xff0c;展示联合编程…

Hadoop调度器深度解析:FairScheduler与CapacityScheduler的优化策略

Hadoop调度器概述在大数据处理的生态系统中&#xff0c;Hadoop作为分布式计算框架的核心&#xff0c;其资源调度机制直接决定了集群的吞吐效率和作业执行公平性。调度器作为Hadoop资源管理的中枢神经&#xff0c;通过协调计算资源与任务需求之间的动态平衡&#xff0c;成为支撑…

怎么自己搭建云手机

用闲置电脑搭建云手机 确保电脑安装 Ubuntu 20.04&#xff08;或其他支持Docker的Linux系统&#xff09;。 安装 Docker&#xff08;运行云手机的核心工具&#xff09;安装Redroid&#xff08;安卓容器&#xff09;运行安卓容器就欧克啦。 用云服务器搭建&#xff08;适合长…

网关:数据翻译、中转、协议转换与边缘计算

网关&#xff08;Gateway&#xff09;详解&#xff1a;翻译与中转站的核心作用 在计算机网络中&#xff0c;网关&#xff08;Gateway&#xff09;是一个非常重要的概念。它本质上是一个“翻译中转站”&#xff0c;其主要作用是将不同网络之间的数据进行“翻译”&#xff0c;并确…

UE5多人MOBA+GAS 番外篇:使用ECC(UGameplayEffectExecutionCalculation)制作伤害计算的流程

文章目录定义一些属性用于作为伤害基础还有获取要打出去的伤害创建一个ECC&#xff08;里面执行伤害的计算&#xff09;在执行ECC的GE之前需要修改ECC需要调用的值&#xff0c;也可以不改直接计算在属性中监听ECC输出的那个值然后处理扣血定义一些属性用于作为伤害基础还有获取…

SpringBoot实战0-5

接口文档&#xff1a;通俗的讲&#xff0c;接口文档能告诉开发者接口能返回的数据&#xff0c;以及为了获取这些数据&#xff0c;开发者需要输入什么样的数据&#xff0c;请求哪个接口&#xff08;即规范&#xff09;为什么使用接口文档&#xff1a;1、项目开发过程中前后端工程…

二、SpringBoot-REST开发

rest开发&#xff08;表现形式转换&#xff09;&#xff1a; 1、优点&#xff1a;隐藏访问资源的行为&#xff0c;无法通过地址得知对资源是何种操作&#xff0c;书写简化 2、GET查询 POST 新增/保存 PUT&#xff08;修改/更新&#xff09; DELETE&#xff08;删除&#xff09;…

大数据之路:阿里巴巴大数据实践——离线数据开发

数据开发平台 统一计算平台MaxCompute&#xff1a;主要服务于海量数据的存储和计算 &#xff0c;提供完善的数据导入方案&#xff0c; 以及多种经典的分布式计算模型&#xff0c;提供海量数据仓库的解决方案&#xff0c;能够更快速地解决用户的海量数据计算问题&#xff0c;有效…

我的网页聊天室设计

一、需求分析1.用户管理模块注册功能实现一个注册页面。注册页面上包含了一个输入框&#xff0c;输入用户名和密码. 注册成功后可以跳转到登录页面.登录功能实现一个登录页面。登录页面上包含一个输入框。输入用户名和密码. 登录成功后可以跳转到主页面.2.主界面用户信息左上角…

数据结构自学Days10 -- 二叉树的常用实现

✅ 一、为什么要学习二叉树&#xff1f; 1. &#x1f4e6; 组织数据的高效方式 二叉树可以快速插入、删除、查找数据&#xff0c;尤其在平衡时&#xff0c;时间复杂度为 $O(\log n)$。 适合表示分层结构&#xff08;如组织结构、文件系统、语法树&#xff09;。 2. &#x…

Java注解家族--`@ResponseBody`

ResponseBody ResponseBody是 Spring 框架中的一个注解&#xff0c;在基于 Spring 的 Web 开发中扮演着重要角色&#xff0c;以下是对它的详细总结&#xff1a; 1.定义与基本功能 定义&#xff1a;ResponseBody注解用于将 Controller 方法的返回值&#xff0c;通过适当的 HttpM…

react-window 大数据列表和表格数据渲染组件之虚拟滚动

简介 React Window 是一个高效的 React 组件库&#xff0c;专为渲染大数据列表和表格数据而设计。它通过”虚拟化”技术&#xff08;也称为”窗口化”或”列表虚拟化”&#xff09;解决了在 React 应用中渲染大量数据时的性能问题。与传统方法不同&#xff0c;React Window 只…

Eltable tree形式,序号列实现左对齐,并且每下一层都跟上一层的错位距离拉大

要的是如图所示效果序号加个class-name写样式然后给eltable加indent属性就可以了&#xff0c;我设置的25