2023.4.4 二叉搜索树的最小绝对差
530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)
我们知道通过中序遍历得到的二叉搜索树就是一个递增的数组。那么如何才能得到两个节点之间的差值呢,我们应该想到需要记录上一个节点,但是如何在递归中去记录上一个节点呢?实际上,我们只需要定义一个全局变量的节点,初始化为null,进入中序遍历时,令其在中序时等于当前节点这样,当遍历到了叶子结点时,他就会等于叶子结点,而我们的计算操作放在赋值之前,这样就会使得这个指针永远是比当前指针落后一位的。
class Solution {
int min = Integer.MAX_VALUE;
TreeNode pre = null;
public int getMinimumDifference(TreeNode root) {
inorder(root);
return min;
}
public void inorder(TreeNode cur){
if(cur == null){
return;
}
inorder(cur.left);
//先进行计算操作,这样才能保证pre指针在当前指针的前一位
//首先要确保pre已经被赋值了,其次,我们的cur在pre前一位,因此cur的值是严格大于pre的
if(pre != null){
min = Math.min(min,cur.val - pre.val);
}
//将pre指针指向为cur节点
pre = cur;
inorder(cur.right);
}
}
2023.4.4 二叉搜索树的众数
这道题的二叉搜索树可以是大于等于的,那么中序遍历出来的结果,其众数一定是相邻的元素,因此可以利用双指针来判断前后两个数是否相邻从而得到众数。问题:如果统计众数的个数以及对应元素并且当有多个众数时该如何记录?使用数组来记录,构建一个记录众数里面个数的指标。问题:第一次出现的重复元素,我们并不知道它是不是出现次数最多的,要怎么判断能否进入结果数组呢?很简单,我们先不管对于第一次出现的众数,我们记录下其最大长度,然后记录进结果集,当遍历到有最大长度超过它时,删除掉结果集中的元素,更新结果集即可。
class Solution {
int maxCount = 0;
int count = 1;
TreeNode pre = null;
ArrayList<Integer> res;
public int[] findMode(TreeNode root) {
res = new ArrayList<>();
inorder(root);
int[] array = new int[res.size()];
for(int i = 0;i<array.length;i++){
array[i] = res.get(i);
}
return array;
}
public void inorder(TreeNode cur){
if(cur == null){
return;
}
inorder(cur.left);
if(pre == null){
count = 1;
}
else if(pre.val == cur.val ){
count++;
}
else if (pre.val != cur.val){//节点值不同
count = 1;
}
if(count == maxCount){
res.add(cur.val);
}
if(count > maxCount){
res.clear();
res.add(cur.val);
maxCount = count;
}
pre = cur;
inorder(cur.right);
}
}
2023.4.4 二叉树的最近公共祖先
236. 二叉树的最近公共祖先 - 力扣(LeetCode)
想要找到公共祖先,我们首先需要找到两个目标节点,然后找到距离其最近的父节点。显然,我们需要从树的叶子节点开始判断,逐步像根节点回溯,因此我们要使用后序遍历来完成。
首先,模拟过程,当我们找到目标节点过后,将其值返回给父节点,因此我们需要一个节点来接受返回值,并且要分为左右子树的返回值。一旦左子树又返回值,且右子树又返回值,就代表我们找到了该节点。
那么如果只有一边又返回值,一边没有,此时代表当前节点还不是公共祖先,将有返回值的节点继续向上返回。如果两边都没有返回值,代表该路径不存在,直接返回null。
使用递归完成,终止条件:如果当前节点就是p或者q,直接返回当前节点。此外,如果当前节点为空,也直接返回。否则就需要继续遍历。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//终止条件:1.找到了p或者q。2.节点为空
if(root == p || root == q || root == null){
return root;
}
//后序遍历遍历节点,并用新节点来接受返回值
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
//因为存在返回值只有找到或者没找到两种情况。我们我们根据左右子树是否找到节点值来进行条件判断并返回
//左右子树都有返回值,代表当前节点的左右子树存在p,q,就是我们要求的祖先节点,直接返回即可。
if(left != null && right != null){
return root;
}
//只有一边又返回值,代表我们需要返回存在结果的半边子树,将其返回值传递给上层节点继续判断。
if(left != null && right == null){
return left;
}
if(left == null && right != null){
return right;
}
//没有找到节点,即left和right都为null,默认返回null
return null;
}
}
然后上述的思路我们似乎只考虑了两个节点在两边的情况,没有考虑两个节点在一边的情况,假设两个节点同时在一边。如下图所示。
我们根据代码的思路,代码进入左子节点遍历到5就会直接返回,即left = TreeNode(5).
right = null ,那么最终的结果也是返回5这个节点。这似乎不会影响结果。这是因为我们的代码已经把此种情况给考虑进去了,因为如果两个节点同时在一边,那么一定会遍历到其中一个节点,此时直接返回该节点,而另一边节点为null,最终返回的是不为空的节点,因此结果仍然是正确的。