【算法篇】三道题理解什么是递归,回溯和剪枝

devtools/2024/10/20 1:25:36/

递归,回溯,剪枝

        想必大家再学习算法知识的路上经常听到回溯,剪枝类似的概念,对于初学者来说,很容易把他们理解成一种新的算法思想,其实回溯和剪枝只是在递归的基础上稍加修改,对于解决某些特定问题非常有帮助,我从力扣上选了三道题,我会粘贴题目链接,并对每道题进行详细的原理分析,希望大家能坚持看完,绝对能有收获,大家有更好的思路也欢迎大家在评论区交流啊!

 

文章顺序:

题目链接=》算法原理=》代码呈现

思想总结:

回溯:从⼀个初始状态开始,按照⼀定的规则向前搜索,当搜索到某个状态⽆法前进时,回退到前⼀个状态,再按照其他的规则搜索。回溯算法在搜索过程中维护⼀个状态树,通过遍历状态树来实现对所有可能解的搜索。

剪枝:如在二叉树中搜索某数时,通过在递归函数执行之前加一层条件判断的方式判断是否已经找到要找的数了,如果找到了便可以不用进入下面的递归函数,以此实现节省时间和空间的目的。

1. 二叉树剪枝

题目链接:

814. 二叉树剪枝 - 力扣(LeetCode)

算法思路:

        如果我们选择从上往下删除,我们需要收集左右⼦树的信息,这可能导致代码编写相对困难。然⽽,通过观察我们可以发现,如果我们先删除最底部的叶⼦节点,然后再处理删除后的节点,最终的结果并不会受到影响。
        因此,我们可以采⽤后序遍历的⽅式来解决这个问题。在后序遍历中,我们先处理左⼦树,然后处理右⼦树,最后再处理当前节点。在处理当前节点时,我们可以判断其是否为叶⼦节点且其值是否为 0,如果满⾜条件,我们可以删除当前节点。
  • 需要注意的是,在删除叶⼦节点时,其⽗节点很可能会成为新的叶⼦节点。因此,在处理完⼦节点后,我们仍然需要处理当前节点。这也是为什么选择后序遍历的原因(后序遍历⾸先遍历到的⼀定是叶⼦节点)。
  • 通过使⽤后序遍历,我们可以逐步删除叶⼦节点,并且保证删除后的节点仍然满⾜删除操作的要求。这样,我们可以较为⽅便地实现删除操作,⽽不会影响最终的结果。
  • 若在处理结束后所有叶⼦节点的值均为 1,则所有⼦树均包含 1,此时可以返回。

代码呈现:

class Solution {public TreeNode pruneTree(TreeNode root) {return dfs(root);}private TreeNode dfs(TreeNode root){if(root==null){return root;}if(root.left==null&&root.right==null){if(root.val==0){return null;}else{return root;}}TreeNode left=dfs(root.left);TreeNode right=dfs(root.right);root.left=left;root.right=right;if(left==null&&right==null&&root.val==0){root=null;}return root;}
}

2.二叉搜索树中第k小的元素

题目链接: 

230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)

算法思路:

算法流程:
定义⼀个全局的变量 count,在主函数中初始化为 k 的值(不⽤全局也可以,当成参数传⼊递归过程中)。
递归函数的设计:int dfs(TreeNode* root): (返回值为第 k 个结点)。
递归函数流程(中序遍历):
1.递归出⼝:空节点直接返回 -1,说明没有找到;
2.去左⼦树上查找结果,记为 retleft:
  • 如果 retleft == -1,说明没找到,继续执⾏下⾯逻辑;
  • 如果 retleft != -1,说明找到了,直接返回结果,⽆需执⾏下⾯代码(剪枝);
3.如果左⼦树没找到,判断当前结点是否符合:
  • 如果符合,直接返回结果
4.如果当前结点不符合,去右⼦树上寻找结果。

代码呈现:

class Solution {int ret;int n;public int kthSmallest(TreeNode root, int k) {n=k;return dfs(root);   }private int dfs(TreeNode root){if(n==0) return ret;if(root.left==null&&root.right==null){if(n!=0){n--;ret=root.val;}return ret;} if(root.left!=null) dfs(root.left);if(n!=0){n--;ret=root.val;}if(n==0) return ret;if(root.right!=null) dfs(root.right);return ret;}
}

3.二叉树的所有路径

题目链接:

257. 二叉树的所有路径 - 力扣(LeetCode)

算法思路:

使⽤深度优先遍历(DFS)求解。
路径以字符串形式存储,从根节点开始遍历,每次遍历时将当前节点的值加⼊到路径中,如果该节点为叶⼦节点,将路径存储到结果中。否则,将 "->" 加⼊到路径中并递归遍历该节点的左右子树。
定义⼀个结果数组,进⾏递归。递归具体实现⽅法如下:
  1. 如果当前节点不为空,就将当前节点的值加⼊路径 path 中,否则直接返回;
  2. 判断当前节点是否为叶⼦节点,如果是,则将当前路径加⼊到所有路径的存储数组 paths 中;
  3. 否则,将当前节点值加上 "->" 作为路径的分隔符,继续递归遍历当前节点的左右⼦节点。
  4. 返回结果数组。
特别地,我们可以只使⽤⼀个字符串存储每个状态的字符串,在递归回溯的过程中,需要将路径中的当前节点移除,以回到上⼀个节点。
具体实现⽅法如下:
  1. 定义⼀个结果数组和⼀个路径数组。
  2. 从根节点开始递归,递归函数的参数为当前节点、结果数组和路径数组。                                      
    a. 如果当前节点为空,返回。
    b. 将当前节点的值加⼊到路径数组中。
    c. 如果当前节点为叶⼦节点,将路径数组中的所有元素拼接成字符串,并将该字符串存储到结果数组中。
    d. 递归遍历当前节点的左⼦树。
    e. 递归遍历当前节点的右⼦树。
    f. 回溯,将路径数组中的最后⼀个元素移除,以返回到上⼀个节点。
  3. 返回结果数组。

代码呈现:

class Solution {List<String> ret=new ArrayList<>();public List<String> binaryTreePaths(TreeNode root) {String path="";dfs(root,path);return ret;}private void dfs(TreeNode root,String path){if(root.left==null&&root.right==null){path+=""+root.val;ret.add(path);return;}path+=root.val+"->";if(root.left!=null){dfs(root.left,path);}if(root.right!=null) dfs(root.right,path);return;}    
}

❤️😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍

🍔我是小皮侠,谢谢大家都能看到这里!!

🦚主页已更新Java基础内容,数据结构基础,数据库,算法,Redis相关内容。

🚕未来会更新Java项目,SpringBoot,docker,mq,微服务以及各种Java路线会用到的技术。

🎃求点赞!求收藏!求评论!求关注!

🤷‍♀️谢谢大家!!!!!!!!


http://www.ppmy.cn/devtools/125257.html

相关文章

81 NAT-静态NAT

一 NAT 出口方向实验 1 配置接口的IP地址 2 配置nat 静态映射 3 测试 无法ping 通 202.38.1.100 4 接口上开启静态Nat映射规则 [FW-Router-BJ-GigabitEthernet0/1]nat static enable 6 5 查看配置 [FW-Router-BJ]display nat static 6 测试 7 查看NAT 会话状态 8 静态…

常见的负载均衡

1.常见的负载均衡服务 负载均衡服务是分布式系统中用于分配网络流量和请求的关键组件&#xff0c;它可以帮助提高应用程序的可用性、可扩展性和响应速度。以下是一些常用的负载均衡服务&#xff1a; Nginx&#xff1a;一个高性能的Web服务器和反向代理&#xff0c;广泛用于实现…

Django一分钟:在Django中怎么存储树形结构的数据,DRF校验递归嵌套模型的替代方案

引言 在开发过程中我们可能需要这样的树形结构: [{"data": {"name": "牛奶"},"children": [{"data": {"name": "蒙牛"}, },{"data": {"name": "伊利"}, }]},{"da…

[论文阅读] MoAI: Mixture of All Intelligence for Large Language and Vision Models

原文链接&#xff1a;http://arxiv.org/abs/2403.07508 源码链接&#xff1a;https://github.com/ByungKwanLee/MoAI 启发&#xff1a;这篇文章提供一个比较新奇的思路&#xff0c;将传统CV小模型的输出进行语言化&#xff0c;转换成统一格式&#xff0c;传入到后续的模型中&…

React和Vue区别,以及注意事项

目录 一、语法和框架特性的差异 二、开发习惯和注意事项 三、特别注意事项 一、语法和框架特性的差异 模板语法&#xff1a; Vue使用了类似于传统HTML的模板语法&#xff0c;通过双大括号{{ }}进行插值&#xff0c;而React则使用了JSX语法。在Vue中&#xff0c;你可以直接在…

ML 系列:机器学习和深度学习的深层次总结(16) — 提高 KNN 效率-使用 KD 树和球树实现更快的算法

一、说明 在机器学习系列的第 16 节&#xff0c;我们重点介绍了提高 K 最近邻 &#xff08;KNN&#xff09; 算法的效率&#xff0c;这是一种广泛用于分类和回归任务的方法。虽然 KNN 简单有效&#xff0c;但对于大型数据集来说&#xff0c;其计算成本可能会令人望而却步。为了…

前端开发笔记--css 黑马程序员1

文章目录 1. css 语法规范2.css的书写风格3.基础选择器选择器的分类标签选择器类选择器类选择器的特殊使用--多类名 id 选择器 字体属性常见字体字体大小字体粗细字体倾斜字体的复合简写字体属性总结 文本属性文本颜色文本对齐装饰文本文本缩进文本间距文本属性总结 css的引入方…

入门篇-1 数据结构简介

数据结构简介 在计算机科学中&#xff0c;数据结构是指组织、存储和管理数据的方式&#xff0c;它使得数据可以被高效地访问和修改。数据结构是计算机程序设计和算法分析中的一个重要概念&#xff0c;因为它们直接影响到程序的执行效率和内存使用。 1. 什么是数据结构&#x…