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

代码随想录C++算法训练,二叉树(day18)

二叉搜索树的最小绝对差

题目链接:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

题目描述:

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

示例 1:

输入:root = [4,2,6,1,3]
输出:1

示例 2:

输入:root = [1,0,48,null,null,12,49]
输出:1

题解:

/**
 * 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 {
private:
    int result = INT_MAX; // 初始化结果为整型最大值,用于后续比较
    TreeNode* pre = nullptr; // 用于记录中序遍历过程中的前一个节点

    // 递归遍历函数,计算BST中任意两节点的最小差值
    void traversal(TreeNode* cur) {
        // 递归终止条件:当前节点为空时直接返回
        if (cur == nullptr) return;

        // 1. 递归遍历左子树(中序遍历的第一步:左)
        traversal(cur->left);

        // 2. 处理当前节点(中序遍历的第二步:根)
        if (pre != nullptr) { // 如果前一个节点不为空(说明不是第一个节点)
            // 计算当前节点与前一个节点的差值,并更新全局最小差值
            result = min(result, cur->val - pre->val);
        }
        pre = cur; // 更新pre为当前节点,供下一次比较使用

        // 3. 递归遍历右子树(中序遍历的第三步:右)
        traversal(cur->right);
    }

public:
    // 对外接口:返回BST中任意两节点的最小差值
    int getMinimumDifference(TreeNode* root) {
        traversal(root); // 调用递归函数遍历整棵树
        return result; // 返回计算得到的最小差值
    }
};

总结与思考:

  • 此题与验证二叉搜索树逻辑相似,对应力扣98题,我们可以将给出的二叉搜索树转化为有序数组后,再进行最小绝对差的计算,或者可以直接在二叉搜索树中进行操作,我们这里直接选择在二叉搜索树中进行操作。
  • 递归要注意的三个重点:
  1. 递归函数的参数和返回值:cur作为当前正在处理的树节点,因为该函数不需要直接返回计算结果,而是通过修改类的成员变量result和pre来记录状态,因此不需要返回值,类型为void
  2. 递归函数的结束条件:当递归到空节点时,说明遍历结束,退出递归
  3. 递归函数单层递归的逻辑:递归遍历左子树,随后进行根进行处理,再递归遍历右子树,重点为对根的处理逻辑,计算当前节点与前一个节点的差值,并更新全局的最小差值

二叉搜索树中的众数

题目链接:501. 二叉搜索树中的众数 - 力扣(LeetCode)

题目描述:

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

示例 1:

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

题解:

/**
 * 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 {
private:
    int maxCount = 0;//最大频率
    int count = 0;//统计频率
    TreeNode* pre = nullptr;//指向前一个元素
    vector<int> result;//统计结果的数组
    void searchBST(TreeNode* cur){
        if(cur == nullptr) return;
        //按照左中右的顺序进行递归和处理
        searchBST(cur->left);

        //重点处理“中”的逻辑
        if(pre == nullptr){//第一个节点
            count = 1;
        }else if(pre->val == cur->val){//当前节点与前一个节点值相同,则频率加一
            count++;
        }else{//不同时,频率不加
            count = 1;
        }
        //更新上一个节点
        pre = cur;

        //统计众数结果
        if(count == maxCount){//如果统计频率与最大频率相同,则将值放入到结果数组中
            result.push_back(cur->val);
        }
        if(count > maxCount){//如果计数大于最大频率
            maxCount = count;//更新最大频率
            result.clear();//若count>maxCount,则之前统计的result失效,需要清空
            result.push_back(cur->val);//放入到结果数组中
        }

        searchBST(cur->right);

        return;
    }
public:
    vector<int> findMode(TreeNode* root) {
        int count = 0;
        int maxCount = 0;
        TreeNode* pre = nullptr;//记录前一个节点
        result.clear();

        searchBST(root);
        return result;
    }
};

总结与思考:

  • 因为是寻找二叉搜索树中的众数,则其中序遍历一定是有序的,根据这一点我们可以使用中序遍历递归解法
  • 该递归函数通过修改类的成员变量result和pre来记录状态,我们可以使用pre和cur指针的技巧,弄一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。而且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是比较的第一个元素。
  • 随后就是常规的中序递归的写法,但这里有一个重难点,我们如何将统计出来的众数作为一个结果数组result返回出来,我们可以遍历一次数组,找出其中最大频率对应的结果,将这个结果再遍历放入集合中,但这样效率不高,所以我们需要在处理“中”节点时做一些额外的处理
  • 若找出的统计频率等于最大统计频率,则将这个频率对应下的元素直接放入结果集合中,若找出的统计频率大于最大统计频率,则更新最大统计频率后,将result数组清空,随后再重新将该频率对应下的元素放入结果集合中。这样我们就可以做到只需要遍历一次二叉搜索树,就找出了众数的集合

二叉树的最近公共祖先

题目链接:236. 二叉树的最近公共祖先 - 力扣(LeetCode)

题目描述:

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

题解:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //递归结束条件,找到q或p或为空时,返回对应结果
        if(root == q || root == p || root == NULL) return root;
        //采用后序遍历,左右中的顺序处理
        //递归左
        TreeNode* left = lowestCommonAncestor(root->left, q, p);
        //递归右
        TreeNode* right = lowestCommonAncestor(root->right, q, p);
        //递归中
        //左右都找到的情况
        if(left != NULL && right != NULL) return root;
        //其他情况
        if(left != NULL && right == NULL) return left;
        else if(left == NULL && right != NULL) return right;
        else{//左右都没找到
            return NULL;
        }
    }
};

总结与思考:

  • 寻找目标的最近公共祖先,我们需要自底向上遍历,因此这里利用回溯的特性:自底向上,而后序遍历的顺序,左右中就是天然的自底向上的过程,因此使用后序遍历递归来解题。
  • 递归需要注意的三个要点:
  1. 递归函数的参数和返回值:我们需要寻找q,p节点的公共祖先root,因此参数为这三个树节点,返回值类型代表着是否找到了公共祖先,因此使用bool型
  2. 递归函数的结束条件:根节点为空的情况下说明是空树,直接返回,若我们找到了p,q时,直接返回节点值。
  3. 递归函数的单层递归逻辑:因为回溯的过程需要递归函数的返回值做判断,所以我们需要遍历整棵树的所有节点,具体的遍历逻辑体现在代码中
http://www.dtcms.com/a/107040.html

相关文章:

  • 辛格迪客户案例 | 盛大康成GMP质量合规数字化(QMS)项目
  • ros2--urdf--IMU
  • uperMap GIS基础产品FAQ集锦(20250402)
  • 「2025最新版React+Ant Design+Router+TailwindCss全栈攻略:从零到实战,打造高颜值企业级应用
  • [ 3分钟算法 ] | 递归搜索题目 : 合并两个有序链表(递归版)
  • C++虚继承及其它特性
  • 智谱发布AI Agent“AutoGLM沉思”,开启AI“边想边干”新时代
  • k8s之Ingress讲解
  • 定制化自己的 RAG 框架:结合 LlamaIndex 与自定义优化
  • c加加学习之day01
  • 解锁Azure Speech “通话转录音分析”功能,驶向服务升级高速路
  • 深度解析 Hive Reduce 数量配置:优化原则与计算公式实战指南
  • TISAX认证是什么?如何获得TISAX认证?对企业发展的好处
  • 尚硅谷shell脚本学习
  • DeepSeek+SpringAI家庭AI医生
  • 高压线防外破警示灯:让隐患无处遁形!/ 恒峰智慧科技
  • mapbox基础,加载hillshade山体阴影图层
  • Docker内网部署前后端分离项目-Windows环境下
  • 代码调试:VS调试实操
  • 民安智库:物业满意度调查是了解业主需求的关键工具
  • spring boot集成reids的 RedisTemplate 序列化器详细对比(官方及非官方)
  • 谷粒微服务高级篇学习笔记整理---thymeleaf
  • Kafka、RocketMQ、Pulsar对比
  • Linux 文件系统超详解
  • Java中的LocalDate类
  • 关于登录鉴权session、cookie和token
  • KMstation商品库存监控下单
  • neo4j+django+deepseek知识图谱学习系统对接前后端分离前端vue
  • angular实现连连看
  • 蓝桥杯练习:二叉树的最大深度