【递归,搜索与回溯算法 & floodfill 算法】深入理解 floodfill 算法:floodfill 算法小专题

【递归,搜索与回溯算法 & floodfill 算法】深入理解 floodfill 算法:floodfill 算法小专题

   

  


图像渲染


    题目解析    



    算法原理    


    解法:暴搜    


     模拟过程     



    递归过程:  



     回溯过程:  



    处理细节问题    


但是如果在上述矩阵的情况下,给我们的 color 不是 2 ,而是 1,也就是原始像素值和要修改像素值相同的情况,此时很有可能在递归的时候走重复路径:

我们不处理好这种特殊的情况,就很容易会写出 bug;所以在编写代码的时候,我们先判断一下,if (image[sr][sc]==color),直接返回即可,因为无需修改; 


    编写代码    


 报错原因:没有修改 image[ sr ][ sc ] 为 color



优化:本题并不需要 vis 数组来标记走过的格子,因为走过的格子都会修改,修改后会被剪枝条件筛查掉,并且这道题也没有递归出口,也不需要恢复现场;


岛屿数量


    题目解析    




    算法原理    


    解法:暴搜    



    处理细节问题     


 为了避免走重复路径,我们定义一个 vis ,用来标记已经走过的小方格 :


    编写代码    



报错原因:

剪枝条件 grid[ x ][ y ] == ' 1 ' ,而不是 grid[ x ][ y ] ==  1;

ret++ 设置的位置不对,是统计完一块岛屿的时候,ret 才+1,而上面这样设置,是在一块陆地(一个小格子)上下左右都查找完之后 +1,而不是找到一个完整的岛屿,ret 才+1;

在下图 ret++ 设置的位置,表示以 grid[ i ][ j ] 这块陆地开始递归,向外查找别的陆地,直到找完整块联通的陆地,递归才会结束;

递归结束,表明已经找到了以 grid[ i ][ j ] 这块陆地为起点所形成的一个完整的岛屿,ret++;


    fillflood 部分     


    思考 :做了那么多题目,为什么有的题目需要恢复现场,有的题目不需要恢复现场呢?   

恢复现场是因为决策树衍生出的多条分支,为了保证每条分支的结果,不被同层的其他已经递归过的分支影响,回溯时,就要把其他分支修改的 path 还原;

而这道题不用恢复现场,原因是因为大多数 fullfill 算法类型的题,是要找出一块矩阵所有的联通区,这些联通区需要被记录,因为这些联通区都会参与最终结果,且各个联通区不会出现重叠,所以在回溯时不需要也不能把记录过的联通区还原;

岛屿的最大面积


    题目解析    



    算法原理    



    解法:暴搜    



     编写代码    



报错原因:count 设置为  dfs 的一个参数,无法记录整个岛屿的面积,会出现只记录一部分,回溯时把记录部分恢复的情况; 



被围绕的区域


    题目解析    


难点:如果联通的 O 区域中,只要有一块能在矩阵的边上,那么这一整块联通区 O 都不能被 X 包围,而这道题的难点就是处理这种情况;


    算法原理    


    解法一:直接使用 floodfill 算法进行深度优先遍历   


我们对一个联通区进行深度优先遍历,直到修改完联通区所有的 O ,但是如果遇到一块非法 O,我们就向上回溯,并且把修改成 X 的 O 全部恢复;

这个思路是可以的,但是代码会非常难写,因为被包围的联通区,和未被包围的联通区深度优先遍历的处理方法是不同的,按照这个思路,我们就需要写两份 dfs ;

并且还有一个更致命的问题,就是我们在进行深度优先遍历时,是先搜索,才能对一块小方块的合法与否进行判断,那么在判断之前,我们并不知道应该调用哪一份 dfs ;


    解法二:正难则反    


如果直接上手写代码比较难的话,我们可以采用正难则反的方法;

处理与边界相连的区域不好上手;那么我们就可以先处理矩阵的最外围,当最外围出现 O,就把O所在的联通区标记一下,此时剩下的 O ,就是我们应该处理的; 


所以,我们可以在真正处理矩阵联通区之前,先扫描矩阵的四条边,如果四条边上扫描到 O, 我们就对这个 O 进行深度优先遍历,标记遍历到的联通区,剩下的联通区就是我们要处理的;


    处理细节问题    


这道题的标记方法,修改原始矩阵会比设置 vis 数组更好,因为这道题本来就是要修改原始矩阵:


    编写代码    


    大体框架    



    fillflood 部分     



    总结    

本题,我们又学会了正难则反的思想,以及如何遍历矩阵的四条边; 

太平洋大西洋水流问题


    题目解析    


在看这道题之前,我们先来看看题目讨论: 


 这道题上面的题目的文字我们可以不看,煮啵会用示例一,来讲清楚这道题要我们做什么;




    算法原理    


    解法一:枚举所有点并且直接判断     


我们可以暴力枚举所有的点,如果一个点可以流向大西洋和太平洋,我们就把这个点的坐标存到最终的 ret 中 ;


如果直接判断,代码虽然不难写,但是会判断很多重复的路径:

 比如图中这个 4,如果想去太平洋,可以通过暴搜,找到所有流向中,其中能流向太平洋的一条路径:


然后我们再来枚举高度为 5 的小格子,就有可能会判断到重复的路径:

枚举小方格使用直接判断的方法,是会判断多次重复路径的,如果这个矩阵的范围非常大,那么无效的时间开销也会变得非常大 ;


    解法二:正难则反   



我们最终要找的是某个点能不能流向太平洋,那我们就反过来看,我们可以假设太平洋的水逆着流,会流向哪些位置(水从海拔低的格子逆着流向海拔高或者等海拔的格子) 


为了降低时间复杂度,遍历过的格子,就不用重新遍历: 


而能流向大西洋的格子同理,让大西洋的水逆向流:


此时,重复的格子就是我们最终的返回值 ,这些重复格子既可以流向太平洋,也可以流向大西洋:


    处理细节问题     



    编写代码    


    大框架    



    fillflood 部分    



par ,atl 作为 dfs 的参数,把 par ,atl 设置成全局变量也可以,设置成局部变量也可以,都能起到记录的结果不会被自动恢复作用;


扫雷游戏


    题目解析    




    算法原理    


算法原理就是扫雷游戏的规则,我们可以自己去玩两把感受一下; 


    解法:模拟 + fillflood 深搜     


我们以示例一来讲解扫雷游戏的步骤: 


 对于扫雷游戏:



    处理细节问题    


本题是八联通,需要扩展向量数组:


    编写代码    


    准备工作    



    核心代码    



机器人的运动范围


    题目解析    




    原题    

地上有一个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。请问该机器人能够到达多少个格子? 

    算法原理    


    解法:深度优先遍历   


 通过一次深度优先遍历,找到满足:  digit(i) + digit(j) <= cnt 性质的格子即可,本题的算法原理很简单,考验的是我们的代码能力;


    编写代码    



报错原因:不定义标记数组,ret 会统计重复走过的格子和递归回溯经过的格子的总数:


     准备工作    



    核心代码    



   

Read more

STM32CubeMX、MDK(Keil MDK)、git、vscode等工具中统一编码设置(UTF-8),确保中文支持,避免乱码问题

STM32CubeMX、MDK(Keil MDK)、git、vscode等工具中统一编码设置(UTF-8),确保中文支持,避免乱码问题 * STM32CubeMX、MDK(Keil MDK)、git、vscode等工具中统一编码设置(UTF-8),确保中文支持,避免乱码问题 * 一、STM32CubeMX 编码设置 * 二、Keil MDK 编码设置 * 三、Git 编码设置 * 四、VS Code设置UTF-8编码 * 五、统一工作流建议 * MDK编码格式为UTF-8,stm32的printf中文输出到串口调试软件,中文显示乱码 * SecureCRT: * Xshell: * Putty: * MobaXterm: * 串口调试助手(如SSCOM、AccessPort等): * 如果串口调试软件不支持UTF-8编码: STM32CubeMX、MDK(Keil MDK)、git、vscode等工具中统一编码设置(

By Ne0inhk

仅限今日开源!基于Python的高性能JSON结构化编辑器架构详解

第一章:Python高性能JSON编辑器概述 在现代软件开发中,JSON(JavaScript Object Notation)作为轻量级的数据交换格式被广泛使用。随着数据规模的不断增长,对JSON文件的高效读取、编辑和写入操作提出了更高要求。传统的文本编辑方式已难以满足大型JSON文件的处理需求,因此构建一个基于Python的高性能JSON编辑器成为提升开发效率的关键工具。 核心特性 * 支持大文件流式解析,避免内存溢出 * 提供语法高亮与结构化视图,增强可读性 * 实现快速搜索与路径定位功能 * 集成校验机制,确保JSON格式合法性 技术选型对比 库名称解析速度内存占用适用场景json (标准库)中等高小到中型文件ujson高低高性能需求ijson低极低超大文件流式处理 基础解析示例 # 使用ijson进行流式解析,适用于大文件 import ijson def stream_parse_json(file_path): with open(file_path, 'rb') as f: # 逐个解析JSON对象中的事件流 parser = ijson.

By Ne0inhk
Git从零到远程协作:手把手实战指南

Git从零到远程协作:手把手实战指南

目录 序言:认识Git 1. 启程 - 安装与初体验    1.1 踏上Git之旅 - 下载与安装    1.2 第一次亲密接触 - 基础配置与仓库创建 2. 核心引擎 - 提交、历史与工作流    2.1 理解Git的“魔法” - 工作区、暂存区与仓库    2.2 记录你的足迹 - 添加(git add)与提交(git commit)    2.3 时光回溯 - 查看历史与差异(git diff) 3. 协作基石 - 分支与合并

By Ne0inhk