第六章 二叉树part06

二叉搜索树的最小绝对差

题目描述

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

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

示例 1:

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

示例 2:

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

解题思路

整体思路: 通过中序遍历依次计算相邻节点值的最小差值,将差值返回。

递归流程说明:

1. 递归函数的参数和返回值

  • 参数:当前遍历的节点。
  • 返回值:无返回值,因为结果是通过类的成员变量 result 来更新的。

2. 递归函数的终止条件

  • 终止条件:若当前节点为空,不需要继续遍历。

3. 递归函数的单层逻辑

  • 左子树遍历:递归调用自身遍历当前节点的左子树。

  • 处理当前节点

    • 如果 pre 不为空,计算当前节点值与前一个节点值的差值,并更新 result 为较小的值。
    • 更新 pre 为当前节点 cur,表示当前节点将成为下一个节点的前一个节点。
  • 右子树遍历:递归调用自身遍历当前节点的右子树。

代码实现

测试地址:https://leetcode.cn/problems/minimum-absolute-difference-in-bst/

class Solution {
private:
    int result = INT_MAX; // 用于存储最小差值的结果
    TreeNode* pre = nullptr; // 用于存储前一个访问的节点

    // 递归遍历函数
    void traversal(TreeNode *cur) {
        if (cur == nullptr) // 终止条件:当前节点为空
            return;
        traversal(cur->left); // 递归遍历左子树
        if (pre != nullptr) { // 如果前一个节点不为空
            result = min(result, cur->val - pre->val); // 更新最小差值
        }
        pre = cur; // 更新前一个节点为当前节点
        traversal(cur->right); // 递归遍历右子树
    }

public:
    int getMinimumDifference(TreeNode *root) {
        traversal(root); // 从根节点开始遍历
        return result; // 返回最小差值
    }
};

二叉搜索树中的众数

题目描述

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

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

假定 BST 满足如下定义:

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

示例 1:

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

示例 2:

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

解题思路

递归流程说明:

1. 递归函数的参数和返回值

  • 参数:当前遍历的节点。
  • 返回值:无返回值,因为结果是通过类的成员变量 result 来更新的。

2. 递归函数的终止条件

  • 终止条件:当前节点为空,不需要继续遍历。

3. 递归函数的单层逻辑

  • 左子树遍历:递归调用自身遍历当前节点的左子树。

  • 处理当前节点

    • 如果 pre 为空,表示当前节点是第一个节点,初始化 count 为 1。
    • 如果 pre 不为空且 pre->val 等于 cur->val,表示当前节点值与前一个节点值相同,增加 count
    • 如果 pre 不为空且 pre->val 不等于 cur->val,表示当前节点值与前一个节点值不同,重置 count 为 1。
    • 更新 pre 为当前节点 cur
  • 更新众数结果

    • 如果 count 等于 maxCount,将当前节点值添加到结果集 result 中。
    • 如果 count 大于 maxCount,更新 maxCountcount,清空结果集 result,并将当前节点值添加到结果集 result 中。
  • 右子树遍历:递归调用自身遍历当前节点的右子树。

代码实现

测试地址:https://leetcode.cn/problems/find-mode-in-binary-search-tree/

class Solution {
private:
    int count = 0; // 用于记录当前元素的频率
    int maxCount = 0; // 用于记录最大频率
    vector<int> result; // 用于存储众数结果
    TreeNode *pre = nullptr; // 用于存储前一个访问的节点

    // 递归遍历函数
    void traversal(TreeNode *cur) {
        if (cur == nullptr) // 终止条件:当前节点为空
            return;
        traversal(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(); // 清空结果集
            result.push_back(cur->val); // 添加当前节点值到结果集
        }

        traversal(cur->right); // 递归遍历右子树
        return;
    }

public:
    // 查找二叉搜索树中的众数
    vector<int> findMode(TreeNode *root) {
        count = 0; // 初始化计数器
        maxCount = 0; // 初始化最大频率
        pre = nullptr; // 初始化前一个节点
        result.clear(); // 清空结果集
        traversal(root); // 从根节点开始遍历
        return result; // 返回众数结果
    }
};

二叉树的最近公共祖先

题目描述

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

百度百科中最近公共祖先的定义为:“对于有根树 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

解题思路

整体思路:通过后序遍历的方式,从叶子节点向上回溯,找到第一个同时包含 pq 的节点,即为最近公共祖先。

递归流程:

1. 递归函数的参数和返回值

  • 参数

    • TreeNode *root:当前遍历的节点。
    • TreeNode *p:第一个目标节点。
    • TreeNode *q:第二个目标节点。
  • 返回值:返回 TreeNode*,即找到的最近公共祖先节点。

2. 递归函数的终止条件

  • 如果当前节点 rootpq 之一或者为空(nullptr),直接返回当前节点 root

    • 如果当前节点是 pq,那么它可能是 LCA 的一部分。因此,我们直接返回当前节点 root
    • 如果当前节点 root 为空,这意味着我们已经到达了树的底部,没有更多的节点可以搜索,直接返回空

3. 递归函数的单层逻辑

  • 左子树遍历:递归遍历左子树,寻找 pq 的最近公共祖先,结果存储在 left 中。

  • 右子树遍历:递归遍历右子树,寻找 pq 的最近公共祖先,结果存储在 right 中。

  • 结果判断

    • 如果 leftright 都不为空,说明 pq 分别在当前节点的左右子树中,当前节点即为最近公共祖先,返回 root
    • 如果 left 为空,说明 pq 都在右子树中,返回 right
    • 如果 right 为空,说明 pq 都在左子树中,返回 left

代码实现

测试地址:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/

class Solution {
public:
    TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
        // 终止条件:如果当前节点是p、q之一或者为空,直接返回当前节点
        if (root == q || root == p || root == nullptr)
            return root;
  
        // 递归遍历左子树,寻找p和q的最近公共祖先
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        // 递归遍历右子树,寻找p和q的最近公共祖先
        TreeNode *right = lowestCommonAncestor(root->right, p, q);
  
        // 如果左子树和右子树都找到了p或q,说明当前节点是最近公共祖先
        if (left != nullptr && right != nullptr)
            return root;
  
        // 如果左子树没有找到p或q,返回右子树的结果
        if (left == nullptr)
            return right;
  
        // 如果右子树没有找到p或q,返回左子树的结果
        return left;
    }
};
  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值