[豪の算法奇妙冒险] 代码随想录算法训练营第十八天 | 530-二叉搜索树的最小绝对差、501-二叉搜索树中的众数、236-二叉树的最近公共祖先

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


LeetCode530 二叉搜索树的最小绝对差

题目链接:https://leetcode.cn/problems/minimum-absolute-difference-in-bst/description/

文章讲解:https://programmercarl.com/0530.二叉搜索树的最小绝对差.html

视频讲解:https://www.bilibili.com/video/BV1DD4y11779/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 由于二叉搜索树的特性,产生最小绝对差的两个节点绝对是相邻节点,所以先采用中序遍历得到二叉搜索树的一个递增序列,然后再依次找出最小差值即为答案

image-20251214170924049

class Solution {
    List<Integer> arr = new ArrayList<>();
    public int getMinimumDifference(TreeNode root) {
        midOrder(root);
        int minDiff = Math.abs(arr.get(0) - arr.get(1));
        for(int i = 2; i < arr.size(); i++){
            int curDiff = Math.abs(arr.get(i) - arr.get(i-1));
            if(curDiff < minDiff){
                minDiff = curDiff;
            }
        }
        return minDiff;
    }

    public void midOrder(TreeNode node){
        if(node == null){
            return;
        }

        if(node.left != null){
            midOrder(node.left);
        }
        arr.add(node.val);
        if(node.right != null){
            midOrder(node.right);
        }
    }
}

​ 利用双指针的思路,还可以避免开辟额外的数组空间,进一步优化代码

image-20251214172516129

class Solution{
    int result = Integer.MAX_VALUE;
    TreeNode preNode = null;
    public void midOrder(TreeNode node){
        if(node == null){
            return;
        }

        midOrder(node.left);
        if(preNode != null){
            int curDiff = Math.abs(preNode.val - node.val);
            if(curDiff < result){
                result = curDiff;
            }
        }
        preNode = node;
        midOrder(node.right);
    }

    public int getMinimumDifference(TreeNode root){
        midOrder(root);
        return result;
    }
}

LeetCode501 二叉搜索树中的众数

题目链接:https://leetcode.cn/problems/find-mode-in-binary-search-tree/description/

文章讲解:https://programmercarl.com/0501.二叉搜索树中的众数.html

视频讲解:https://www.bilibili.com/video/BV1fD4y117gp/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 一开始想到的是暴力求解,先中序遍历一遍二叉树,用HashMap存储每个元素出现的次数,然后再遍历两遍HashMap,第一遍得到最多的次数,第二遍收集众数

​ 虽然能AC,但代码显然不够优雅,而且也没用上二叉排序树的特性

image-20251214193146605

class Solution {
    HashMap<Integer, Integer> map = new HashMap<>();
    public int[] findMode(TreeNode root) {
        midOrder(root);
        int maxCnt = Integer.MIN_VALUE;
        for(Map.Entry<Integer, Integer> curNode : map.entrySet()){
            int value = curNode.getValue();
            if(value > maxCnt){
                maxCnt = value;
            }
        }
        ArrayList<Integer> records = new ArrayList<>();
        for(Map.Entry<Integer, Integer> curNode : map.entrySet()){
            if(curNode.getValue() == maxCnt){
                records.add(curNode.getKey());
            }
        }
        int[] result = new int[records.size()];
        for(int i = 0; i < records.size(); i++){
            result[i] = records.get(i);
        }
        return result;
    }

    public void midOrder(TreeNode node){
        if(node == null){
            return;
        }
        midOrder(node.left);
        map.put(node.val, map.getOrDefault(node.val, 0) + 1);
        midOrder(node.right);
    }
}

​ 用双指针遍历二叉搜索树,记录maxCount,同步更新result数组,这样一次遍历就可以找到所有众数,大幅优化执行用时

image-20251214202134861

class Solution{
    ArrayList<Integer> records = new ArrayList<>();
    int count = 0;
    int maxCount = 0;
    TreeNode preNode = null;
    public void midOrder(TreeNode node){
        if(node == null){
            return;
        }

        midOrder(node.left);
        
        if(preNode == null|| preNode.val != node.val){
            count = 1;
        }else {
            count++;
        }

        if(count == maxCount){
            records.add(node.val);
        }else if(count > maxCount){
            maxCount = count;
            records.clear();
            records.add(node.val);
        }
        preNode = node;

        midOrder(node.right);
    }

    public int[] findMode(TreeNode root){
        midOrder(root);
        int[] result = new int[records.size()];
        for(int i = 0; i < records.size(); i++){
            result[i] = records.get(i);
        }
        return result;
    }
}

LeetCode236 二叉树的最近公共祖先

题目链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/

文章讲解:https://programmercarl.com/0236.二叉树的最近公共祖先.html

视频讲解:https://www.bilibili.com/video/BV1jd4y1B7E2/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 求最小公共祖先,需要从底向上遍历,二叉树只能通过后序遍历(即:回溯)实现从底向上的遍历方式

​ 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断

image-20251214204554056

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 null;
        }else if(left == null && right != null){
            return right;
        }else if(left != null && right == null){
            return left;
        }else{
            return root;
        }
    }
}
posted @ 2025-12-14 21:00  SchwarzShu  阅读(2)  评论(0)    收藏  举报