二叉搜索树的最小绝对差
题目描述
给你一个二叉搜索树的根节点 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
,更新maxCount
为count
,清空结果集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
解题思路
整体思路:通过后序遍历的方式,从叶子节点向上回溯,找到第一个同时包含 p
和 q
的节点,即为最近公共祖先。
递归流程:
1. 递归函数的参数和返回值
-
参数:
TreeNode *root
:当前遍历的节点。TreeNode *p
:第一个目标节点。TreeNode *q
:第二个目标节点。
-
返回值:返回
TreeNode*
,即找到的最近公共祖先节点。
2. 递归函数的终止条件
-
如果当前节点
root
是p
、q
之一或者为空(nullptr
),直接返回当前节点root
。- 如果当前节点是
p
或q
,那么它可能是 LCA 的一部分。因此,我们直接返回当前节点root
。 - 如果当前节点
root
为空,这意味着我们已经到达了树的底部,没有更多的节点可以搜索,直接返回空
- 如果当前节点是
3. 递归函数的单层逻辑
-
左子树遍历:递归遍历左子树,寻找
p
和q
的最近公共祖先,结果存储在left
中。 -
右子树遍历:递归遍历右子树,寻找
p
和q
的最近公共祖先,结果存储在right
中。 -
结果判断:
- 如果
left
和right
都不为空,说明p
和q
分别在当前节点的左右子树中,当前节点即为最近公共祖先,返回root
。 - 如果
left
为空,说明p
和q
都在右子树中,返回right
。 - 如果
right
为空,说明p
和q
都在左子树中,返回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;
}
};