代码随想录算法训练营第20天|530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236.二叉树的最近公共祖先

本文介绍了如何使用中序双指针法解决力扣上的三个二叉搜索树相关问题:最小绝对差、查找众数和最近公共祖先。通过递归遍历和双指针技巧,分别实现并优化了算法.
摘要由CSDN通过智能技术生成

一、力扣530.二叉搜索树的最小绝对差

1.1 题目

在这里插入图片描述

1.2 思路

自己的分析:首先关注任意两节点的差的绝对值的最小值,因为所有节点为非负值,所以差的绝对值的最小值一定是出现在从小到大排序相邻两个节点值之间,所以我们可以双指针法中序遍历二叉搜索树,用当前节点的val减去pre节点的val,最后返回一个min值。

1.3 代码

class Solution {
    public Integer min = Integer.MAX_VALUE;
    public TreeNode pre = null;
    public int getMinimumDifference(TreeNode root) {
        //双指针法中序遍历
        //判断特殊情况
        if(root == null){
            return 0;
        }
        inorder(root);
        return min;
    }
    //双指针中序遍历
    public void inorder(TreeNode cur){
        //确定递归终止条件
        if(cur == null){
            return;
        }
        //左中右
        inorder(cur.left);

        if(pre != null){
             min = (cur.val - pre.val) < min ? (cur.val - pre.val): min;
        }
        pre = cur;

        inorder(cur.right);
        return;

    }
}

二、力扣501.二叉搜索树中的众数

2.1 题目

在这里插入图片描述

2.2 思路

普通二叉树暴力想法:遍历+hashmap+排序。
我的想法:中序双指针遍历,将每个val及其出现的频率存入hashmap中,预先设置一个maxTime来记录出现过的最大频率,在遍历结束之后从hashmap中取出频率等于maxTime的key加入数组即可。

代码随想录想法:中序双指针遍历,定义全局变量maxCount,count,以及结果集result集合,每遍历到cur时就判断当前的count是否大于(清除原result,将当前val加入)或者等于maxCount(将当前val加入)。

在这里插入图片描述

2.3 代码

我的想法:(跑出来解答错误,不知道哪里的问题)

class Solution {
    public int maxTime = 0;
    public TreeNode pre = null;
    public Map<Integer,Integer> hashmap = new HashMap<>();
    public int[] findMode(TreeNode root) {
        //自己的中序双指针遍历+hashmap解法
        inorder(root);
        //在hashmap中查询value与maxTime相同的key加入数组
        List<Integer> res = new ArrayList<>();
        Set<Integer> keys = hashmap.keySet();
        for(Integer key : keys){
            if(hashmap.get(key) == maxTime){
                res.add(key);
            }
        }
        int[] result = new int[res.size()];
        for(int i =0;i<result.length;i++){
            result[i] = res.get(i);
        }
        return result;
    }
    //中序遍历
    public void inorder(TreeNode cur){
        //确定递归终止条件
        if(cur == null){
            return;
        }
        inorder(cur.left);

        if(pre != null){
                if(cur.val != pre.val){
                //对比一下pre.val的频率和maxTime,较大者赋值给maxTime,然后pre切换到当前节点
                if(hashmap.get(pre.val) > maxTime){
                    maxTime = hashmap.get(pre.val);
                }
                pre = cur;
            }
         hashmap.put(cur.val,hashmap.getOrDefault(cur.val,0)+1);
        }else{    //以上两种情况都需要将cur.val加入map中
          hashmap.put(cur.val,hashmap.getOrDefault(cur.val,0)+1);
          pre = cur;
        }


        inorder(cur.right);
    }
}

代码随想录想法:

class Solution {
    public int maxCount = 0;
    public int count;
    public List<Integer> res = new ArrayList<>();
    public TreeNode pre = null;
    public int[] findMode(TreeNode root) {
        //中序遍历(双指针)
        traversal(root);
        int[] result = new int[res.size()];
        for(int i =0;i<result.length;i++){
            result[i] = res.get(i);
        }
        return result;
    }
    //中序遍历
    public void traversal(TreeNode root){
        //确定终止条件
        if(root == null){
         return;   
        }

        //左中右
        traversal(root.left);
        //中:处理逻辑,遍历到一个节点就需要更新count的值、比较与maxcount的关系,并且移动指针
        //先处理count的值
        if(pre == null){
            count = 1;
        }else if(pre.val == root.val){
            count++;
        }else{
            count = 1;
        }
        //处理count和maxCount的关系
        if(count >maxCount){
            //清除res,将该节点的值加入,更新maxCount
            res.clear();
            res.add(root.val);
            maxCount = count;
        }else if(count == maxCount){
            //将该节点的值加入
            res.add(root.val);
        }
        //切换pre节点
        pre = root;

        traversal(root.right);

    }
}

2.4 总结

每遍历到一个新节点,先判断更新count的值;然后判断count和maxCount的关系;

三、力扣236.二叉树的最近公共祖先

3.1 题目

在这里插入图片描述
在这里插入图片描述

3.2 思路

确定后序遍历:中要根据左和右的结果来判断。
关键点:后序遍历的递归终止条件!(一种是向下遍历到最底层,遍历到叶子结点的下一个null节点还没有找到p或者q;还有一种是遍历找到了p或者q,那么就没必要再继续向下遍历寻找了!)
考虑本题的两种情况:
(1)
在这里插入图片描述
(2)这种情况其实无需特殊处理,在递归终止条件里的标红部分其实已经解决了。
在这里插入图片描述

3.3 代码

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //注意本题有两种情况,但情况二在实际场景中其实包含在了情况一的处理逻辑中
        return traversal(root,p,q);
    }
    //因为是求最近的公共祖先,所以是自下而上层层返回,需要用到后序遍历
    public TreeNode traversal(TreeNode root,TreeNode p,TreeNode q){
        //确定递归的终止条件(当前节点为null or 找到了p或者q中的某一个)
        if(root == null ||root == p || root == q){
            return root;
        }
        //左右中
        TreeNode left = traversal(root.left,p,q);
        TreeNode right = traversal(root.right,p,q);

        //根据左右返回的结果处理中的逻辑
        if(left == null && right == null){
            return null;
        }else if(left == null && right != null){
            return right;
        }else if(left != null && right == null){
            return left;
        }else{
            return root;
        }

    }
}

3.4 总结

递归终止判断:当前节点为null or p or q就可以直接返回;
中的处理逻辑:
(1)左右均为空:返回空;
(2)左右一个为空,另一个不为空:返回不为空的;
(3)左右均不为空,返回当前节点;(左右分别是p和q)

部分资料来源:https://programmercarl.com/0236.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值