530. 二叉搜索树的最小绝对差
题目:
给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
解题思路:
由于二叉搜索树的中序遍历是有序的,因此可以通过中序遍历逐步比较当前节点和前一个节点的值,更新最小差值。具体步骤如下:
- 初始化结果变量
res
为最大整数值,前一个节点pre
为null
。 - 使用中序遍历对二叉搜索树进行递归遍历。
- 在中序遍历过程中,如果前一个节点
pre
不为空,则计算当前节点与pre
节点值的差,并更新最小差值res
。 - 将当前节点更新为
pre
,继续遍历。 - 最后,返回
res
即为最小绝对差。
代码:
class Solution {
private int res = Integer.MAX_VALUE;
private TreeNode pre = null;
public int getMinimumDifference(TreeNode root) {
helper(root);
return res;
}
public void helper(TreeNode root){
if (root==null){
return;
}
helper(root.left);
if(pre!=null){
res = Math.min(res,root.val-pre.val);
}
pre = root;
helper(root.right);
}
}
501. 二叉搜索树中的众数
题目:
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
解题思路:
由于二叉搜索树的中序遍历是递增有序的,可以通过中序遍历来找到所有的众数。具体步骤如下:
-
变量初始化:
- 使用
maxCount
来记录出现次数的最大值。 count
记录当前节点值的出现次数。pre
用于存储上一个访问的节点,以便判断当前节点是否与前一个节点的值相同。
- 使用
-
中序遍历:
- 使用递归的中序遍历访问二叉搜索树的每个节点。
- 如果当前节点的值与前一个节点相同,则增加
count
。 - 如果不同,则将
count
重置为1
。
-
更新众数列表:
- 当
count
大于maxCount
时,清空modeList
,更新maxCount
,并将当前值加入modeList
。 - 如果
count
等于maxCount
,则直接将当前值添加到modeList
。
- 当
-
返回结果:
遍历完成后,将modeList
转换为数组并返回。
代码:
class Solution {
List<Integer> modeList = new ArrayList<>();
private int maxCount = 0;
private int count = 0;
private TreeNode pre = null;
public int[] findMode(TreeNode root) {
if (root == null) {
return new int[0];
}
helper(root);
int[] res = new int[modeList.size()];
for (int i = 0; i < modeList.size(); i++) {
res[i] = modeList.get(i);
}
return res;
}
public void helper(TreeNode root) {
if (root == null) {
return;
}
helper(root.left);
// 更新当前节点的出现次数
if (pre != null && pre.val == root.val) {
count++;
} else {
count = 1;
}
// 更新 maxCount 和 modeList
if (count > maxCount) {
modeList.clear();
maxCount = count;
modeList.add(root.val);
} else if (count == maxCount) {
modeList.add(root.val);
}
pre = root; // 更新 pre 为当前节点
helper(root.right);
}
}
236. 二叉树的最近公共祖先
题目:
给定一个二叉树,找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
解题思路:
可以通过递归的方式查找两个节点的最近公共祖先。具体思路分为两种方法:
-
方法一:后序遍历递归查找,并利用布尔值返回节点位置。
- 使用递归函数
helper
遍历树的每个节点。 - 定义
left
、right
和mid
分别表示左子树、右子树是否包含p
或q
,以及当前节点是否是p
或q
。 - 当满足
(left && right) || (mid && left) || (mid && right)
时,当前节点为最近公共祖先,将其存入node
。 - 递归返回
mid || left || right
,表示当前子树中是否包含p
或q
。
- 使用递归函数
-
方法二:递归分治法。
- 从根节点开始递归查找
p
和q
。 - 如果当前节点为空或等于
p
或q
,则直接返回当前节点。 - 递归查找左右子树,若
p
和q
分别位于左右子树,则当前节点为最近公共祖先。 - 如果
p
和q
都在左子树或右子树中,则返回找到的子树根节点。
- 从根节点开始递归查找
代码:
class Solution {
private TreeNode node = null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
boolean res = helper(root,p,q);
return node;
}
public boolean helper(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return false;
}
boolean left = helper(root.left,p,q);
boolean right = helper(root.right,p,q);
boolean mid = (root == p || root == q);
if(left && right || left && mid || right && mid){
node = root;
}
return mid || right || left;
}
}
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) { // 若未找到节点 p 或 q
return null;
}else if(left == null && right != null) { // 若找到一个节点
return right;
}else if(left != null && right == null) { // 若找到一个节点
return left;
}else { // 若找到两个节点
return root;
}
}
}