530.二叉搜索树的最小绝对差
题目
给你一个二叉搜索树的根节点 root
,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
示例 1:
输入:root = [4,2,6,1,3]
输出:1
提示:
-
树中节点的数目范围是
[2, 10(4)]
-
0 <= Node.val <= 10(5)
思路
二叉搜索树采用中序遍历,其实就是一个有序数组。
题意理解成在一个有序数组上求两个树最小差值 ,最直观想法:把二叉搜索树转换成有序数组,再遍历一遍数组,就统计出来最小差值了
但用双指针可以直接计算,需要一个 pre 节点记录一下 cur 节点前一个节点
代码实现
class Solution {
private:
int result = INT_MAX;
TreeNode* pre = NULL;
void traversal(TreeNode* cur)
{
if(cur == NULL) return;
traversal(cur->left);
if(pre != NULL){
result = min(result, cur->val - pre->val);
}
pre = cur;
traversal(cur->right);
}
public:
int getMinimumDifference(TreeNode* root) {
traversal(root);
return result;
}
};
501.二叉搜索树中的众数
题目
给你一个含重复值的二叉搜索树(BST)的根节点 root
,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
-
结点左子树中所含节点的值 小于等于 当前节点的值
-
结点右子树中所含节点的值 大于等于 当前节点的值
-
左子树和右子树都是二叉搜索树
示例 1:
输入:root = [1,null,2,2]
输出:[2]
提示:
-
树中节点的数目在范围
[1, 10(4)]
内 -
-10(5) <= Node.val <= 10(5)
思路
与上一题类似,中序遍历二叉搜索树,定义一个 maxCount 和 count,去做判断
判断之后再去处理结果集,当 maxCount 有更新时,result 清空
代码实现
class Solution {
private:
int maxCount = 0;
int count = 0;
vector<int> result;
TreeNode* pre = NULL;
void traversal(TreeNode* cur)
{
if(cur == NULL) return;
traversal(cur->left);
if(pre == NULL) 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);
}
public:
vector<int> findMode(TreeNode* root) {
traversal(root);
return result;
}
};
236. 二叉树的最近公共祖先
题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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, 10(5)]
内。 -
-10(9) <= Node.val <= 10(9)
-
所有
Node.val
互不相同
。 -
p != q
-
p
和q
均存在于给定的二叉树中。
思路
二叉树回溯的过程就是从底向上,后序遍历(左右中)就是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。
情况一:如果找到一个节点,发现左子树出现节点 p,右子树出现节点 q,或者 p q 反过来,那么该节点就是节点 p 和 q 的最近公共祖先。
判断逻辑是,如果递归遍历遇到 q,就将 q 返回,遇到 p 就将 p 返回,那么如果左右子树的返回值都不为空,说明此时的中节点一定是 q 和 p 的最近祖先。
注意,二叉树节点数值不重复,且一定存在 p 和 q
但容易忽略了情况二:节点本身p(q)拥有一个子孙节点q§
但在实现过程中,情况一就已经把情况二包含进去了
递归三部曲:
-
确定递归函数返回值以及参数
-
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
-
-
确定终止条件
- 遇到空,返回空
- 如果 root == q/p,说明找到 q p,将其返回,这个返回值,后面在中节点的处理过程中会用到
-
if(root == q || root == p || root == NULL) return root;
-
确定单层递归逻辑
- 先用 left 和 right 接住左子树和右子树的返回值,代码如下
-
TreeNode* left = lowestCommonAncestor(root->left, p, q); TreeNode* right = lowestCommonAncestor(root->right, p, q);
如果 left 和 right 都不为空,说明此时 root 就是最近公共节点
如果 left 为空,right 不为空,就返回 right,说明目标节点是通过 right 返回,反之亦然
途中节点 10 的做子树返回 null,右子树返回目标值 7,那么此时节点 10 的处理逻辑就是把右子树的返回值(最近公共祖先 7)返回上去
那么如果 left 和 right 都为空,则返回 left 或者 right 都可以,即返回空
if (left == NULL && right != NULL) return right;
else if (left != NULL && right == NULL) return left;
else { // (left == NULL && right == NULL)return NULL;
}
寻找最小公共祖先完整流程图如下:
代码实现
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL || root == p || root == q) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left != NULL && right != NULL)return root;
if(left == NULL) return right;
return left;
}
};