当前位置: 首页 > news >正文

算法导论(递归回溯)——⼆叉树中的深搜

算法思路(129)

前序遍历遵循“根节点、左子树、右子树”的顺序遍历二叉树的所有节点,常用于解决子节点状态依赖于父节点状态的问题。

算法思路:

在前序遍历的过程中,我们可以将信息从节点向左右子树传递,并在回溯时获取左右子树的返回值。递归函数实现了两个主要功能:

  1. 整合父节点的值与当前节点的信息,计算当前节点的数字,并将结果传递到下一层进行递归。
  2. 当遇到叶子节点时,不再向下传递信息,而是将整合后的结果向上回溯至根节点。

在递归结束后,根节点的返回值将更新为整棵树的数字和。

算法流程:

递归函数设计:int dfs(TreeNode* root, int num)

  • 返回值:当前子树的计算结果(数字和)。
  • 参数num  在递归过程中向下传递的父节点的数字信息。
  • 功能:整合父节点与当前节点的信息,计算当前节点的数字,并向下传递,同时在回溯时返回以当前节点为根的子树的数字和。

递归函数流程:

  1. 若当前节点为空,表示路径结束,返回0。
  2. 将父节点传递下来的信息与当前节点的值结合,计算当前节点的数字和 sum
  3. 如果当前节点是叶子节点,则直接返回整合后的结果 sum
  4. 如果当前节点不是叶子节点,将 sum 传递到左右子树,分别计算左右子树的数字和,并将结果相加后返回。

C++:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 * int val;
 * TreeNode *left;
 * TreeNode *right;
 * TreeNode() : val(0), left(nullptr), right(nullptr) {}
 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution 
{
public:
 int sumNumbers(TreeNode* root) 
 {
 return dfs(root, 0);
 }
 int dfs(TreeNode* root, int presum)
 {
 presum = presum * 10 + root->val;
 if(root->left == nullptr && root->right == nullptr)
 return presum;
 int ret = 0;
 if(root->left) ret += dfs(root->left, presum);
 if(root->right) ret += dfs(root->right, presum);
 return ret;
 }
};

Java:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 * int val;
 * TreeNode left;
 * TreeNode right;
 * TreeNode() {}
 * TreeNode(int val) { this.val = val; }
 * TreeNode(int val, TreeNode left, TreeNode right) {
 * this.val = val;
 * this.left = left;
 * this.right = right;
 * }
 * }
 */
class Solution 
{
 public int sumNumbers(TreeNode root) 
 {
 return dfs(root, 0);
 }
 public int dfs(TreeNode root, int preSum)
 {
 preSum = preSum * 10 + root.val;
 if(root.left == null && root.right == null)
 return preSum;
 
 int ret = 0;
 if(root.left != null) ret += dfs(root.left, preSum);
 if(root.right != null) ret += dfs(root.right, preSum);
 return ret;
 } 
}

算法思路(98)

如果一棵树是二叉搜索树(BST),那么它的中序遍历结果一定是一个严格递增的序列。因此,我们可以初始化一个全局变量 prev 用以记录中序遍历过程中的前驱节点。通过在中序遍历过程中判断当前节点与前驱节点的值是否构成递增序列,我们可以有效地验证树是否满足二叉搜索树的特性。

算法流程:

  1. 初始化一个全局变量 prev,用于记录中序遍历过程中前驱节点的值(初始值可以设为负无穷)。

  2. 中序遍历的递归函数流程如下:

    • 递归出口:当 root == nullptr 时,返回 true,表示空树是二叉搜索树。
    • 先递归检查左子树是否满足二叉搜索树的特性,结果存储在 retleft 中。
    • 然后检查当前节点是否满足二叉搜索树的性质,结果存储在 retcur 中:
      • 如果当前节点的值 val 大于 prev,则满足二叉搜索树的条件,将 retcur 标记为 true 并更新 prev 为当前节点的值。
      • 如果当前节点的值 val 小于或等于 prev,则不满足条件,将 retcur 标记为 false
    • 最后递归检查右子树是否满足二叉搜索树的特性,结果存储在 retright 中。
  3. 只有当 retleftretcur 和 retright 全部为 true 时,才能返回 true,说明当前树满足二叉搜索树的所有条件。

C++:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 * int val;
 * TreeNode *left;
 * TreeNode *right;
 * TreeNode() : val(0), left(nullptr), right(nullptr) {}
 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution 
{
 long prev = LONG_MIN;
public:
 bool isValidBST(TreeNode* root) 
 {
 if(root == nullptr) return true;
 bool left = isValidBST(root->left);
 // 剪枝 
 if(left == false) return false;
 bool cur = false;
 if(root->val > prev)
 cur = true;
 // 剪枝 
 if(cur == false) return false;
 prev = root->val;
 bool right = isValidBST(root->right);
 return left && right && cur;
 }
};

Java:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 * int val;
 * TreeNode left;
 * TreeNode right;
 * TreeNode() {}
 * TreeNode(int val) { this.val = val; }
 * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val;
 * this.left = left;
 * this.right = right;
 * }
 * }
 */
class Solution 
{
 long prev = Long.MIN_VALUE;
 public boolean isValidBST(TreeNode root) 
 {
 if(root == null) return true;
 boolean left = isValidBST(root.left);
 // 剪枝 
 if(left == false) return false;
 boolean cur = false;
 if(root.val > prev) cur = true;
 if(cur == false) return false;
 prev = root.val;
 boolean right = isValidBST(root.right);
 return left && cur && right;
 }
}

算法思路(230)

我们可以利用中序遍历的特性,只需扫描前 k 个节点便可找到目标。因此,我们可以创建一个全局计数器 count,初始化为 k,在每次遍历节点时将 count 减一。当 count 的值减至 1 时,表明当前节点就是我们要查找的结果。

算法流程:

  1. 定义一个全局变量 count,在主函数中初始化为 k(也可以作为参数传入递归)。

  2. 递归函数设计:int dfs(TreeNode* root)

    • 返回值为第 k 个节点。
  3. 递归函数流程(中序遍历):

    • 递归出口:如果当前节点为空,直接返回 -1,表示未找到。
    • 先递归遍历左子树查找结果,结果存储在 retleft 中:
      • 如果 retleft == -1,则表示在左子树中未找到,继续执行后续逻辑。
      • 如果 retleft != -1,则表示已找到第 k 个节点,直接返回结果,无需继续执行后续代码(进行剪枝)。
    • 如果左子树未找到,判断当前节点:
      • 如果当前节点是我们要找的目标(count == 1),则返回当前节点。
    • 如果当前节点不符合条件,则递归遍历右子树寻找结果。

C++:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 * int val;
 * TreeNode *left;
 * TreeNode *right;
 * TreeNode() : val(0), left(nullptr), right(nullptr) {}
 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution 
{
 int count;
 int ret;
public:
 int kthSmallest(TreeNode* root, int k) 
 {
 count = k;
 dfs(root);
 return ret;
 }
 void dfs(TreeNode* root)
 {
 if(root == nullptr || count == 0) return;
 dfs(root->left);
 count--;
 if(count == 0) ret = root->val;
 dfs(root->right);
 }
 };

Java:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 * int val;
 * TreeNode left;
 * TreeNode right;
 * TreeNode() {}
 * TreeNode(int val) { this.val = val; }
 * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val;
 * this.left = left;
 * this.right = right;
 * }
 * }
 */
 class Solution 
 {
 int count;
 int ret;
 public int kthSmallest(TreeNode root, int k) 
 {
 count = k;
 dfs(root);
 return ret;
 }
 void dfs(TreeNode root)
 {
 if(root == null || count == 0) return;
 dfs(root.left);
 count--;
 if(count == 0) ret = root.val;
 if(count == 0) return;
 dfs(root.right);
 }
}

http://www.dtcms.com/a/123022.html

相关文章:

  • lanqiaoOJ 498 回文日期
  • ValueError: Cannot handle batch sizes > 1 if no padding token is defined`
  • 数据结构(五)——AVL树(平衡二叉搜索树)
  • 【Python语言基础】17、继承
  • 深入理解 Spring 的 MethodParameter 类
  • 测试的分类
  • OpenCV 图形API(25)图像滤波-----均值滤波(模糊处理)函数blur()
  • 写一个简单的demo来理解数据库外键
  • Java中的参数是值传递还是引用传递?
  • webpack配置导致浏览器自动刷新
  • Pytest+Allure+Excel接口自动化测试框架实战
  • 【Kafka基础】监控与维护:分区健康检查,确保数据高可用
  • 【C++算法】53.链表_重排链表
  • 数据可视化 —— 柱形图应用(大全)
  • 《Uniapp-Vue 3-TS 实战开发》构建HTTP请求拦截器
  • Windows 2016 如何关闭自动更新
  • HLSL Complex Shapes With For Loops
  • Linux启动端口,Windows 看是否通
  • 使用 Vue + PDF.js 构建在线 PDF 阅读器(支持目录与缩放)
  • Petalinux最简开发
  • (2)网络学习之堡垒机
  • 如何避免Python爬虫重复抓取相同页面?
  • 【数据结构】树状数组
  • RTT中断管理学习
  • 苹果电脑MAC系统安装
  • 【MySQL篇】mysqlpump和mysqldump参数区别总汇
  • 【C++游戏引擎开发】第11篇:GLFW、GLAD环境搭建与第一个三角形渲染
  • 09-Spring 与线程安全:IOC 与多线程下的坑与解法
  • 解锁Midjourney创作潜能:超详细提示词(Prompts)分类指南
  • 【42期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深指数最新分时BOLL数据及接口API说明文档