代码随想录算法训练营day21|二叉搜索树的最小绝对差、二叉搜索树的众数、二叉树的最近公共祖先

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 二叉搜索树的众数

501. 二叉搜索树中的众数 - 力扣(LeetCode)

这道题的二叉搜索树可以是大于等于的,那么中序遍历出来的结果,其众数一定是相邻的元素,因此可以利用双指针来判断前后两个数是否相邻从而得到众数。问题:如果统计众数的个数以及对应元素并且当有多个众数时该如何记录?使用数组来记录,构建一个记录众数里面个数的指标。问题:第一次出现的重复元素,我们并不知道它是不是出现次数最多的,要怎么判断能否进入结果数组呢?很简单,我们先不管对于第一次出现的众数,我们记录下其最大长度,然后记录进结果集,当遍历到有最大长度超过它时,删除掉结果集中的元素,更新结果集即可。

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,最终返回的是不为空的节点,因此结果仍然是正确的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值