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

530.二叉搜索树的最小绝对差(BST的中序是有序的)

还是疏忽了……一定要牢记BST的性质
在BST中,最小绝对差不一定出现在父子节点之间,而是可能出现在相邻的中序遍历节点之间。因此,直接比较当前节点与其左右子节点的值是不够的。

class Solution {
    public int getMinimumDifference(TreeNode root) {
        min = Integer.MAX_VALUE;
        getMin(root);
        return min;
    }

    private int min;
    private void getMin(TreeNode node){
        if(node==null) return;
        if(node.left!=null){
            min = min < Math.abs(node.val - node.left.val) ? min : Math.abs(node.val - node.left.val);
            getMin(node.left);
        }
        if(node.right!=null){
            min = min < Math.abs(node.val - node.right.val) ? min : Math.abs(node.val - node.right.val);
            getMin(node.right);
        }
    }
}

BST是有序的,可以视为在一个有序数组上求最值,求差值,这样就简单多了。
思路:

  1. 最直观的想法,就是把二叉搜索树转换成有序数组,然后遍历一遍数组,就统计出来最小差值了(相邻两数的差值)。
  2. 不需要转换为数组:在BST中序遍历的过程中,我们就可以直接计算了。
    需要用一个pre节点记录一下cur节点的前一个节点。
    在中序遍历中,由于cur始终比pre快,因此cur.val - pre.val一定是正数。
    如何实现pre?递归中,处理该节点时,如果有pre就计算,没有就记录为pre(此时是最左节点)。
// 中序递归
class Solution {
    TreeNode pre; // 记录上一个遍历的结点
    int result = Integer.MAX_VALUE;

    public int getMinimumDifference(TreeNode root) {
        if (root == null)
            return 0;
        traversal(root);
        return result;
    }

    public void traversal(TreeNode root) {
        if (root == null)
            return;
        
        // 左
        traversal(root.left); 
        
        // 中
        if (pre != null) {
            result = Math.min(result, root.val - pre.val);
        }
        pre = root;
        
        // 右
        traversal(root.right);
    }
}

// 中序迭代
class Solution {
    TreeNode pre;
    Stack<TreeNode> stack;
    public int getMinimumDifference(TreeNode root) {
        if (root == null) return 0;
        stack = new Stack<>();
        TreeNode cur = root;
        int result = Integer.MAX_VALUE;
        while (cur != null || !stack.isEmpty()) {
            if (cur != null) {
                stack.push(cur); // 将访问的节点放进栈
                cur = cur.left; // 左
            }else {
                cur = stack.pop(); 
                if (pre != null) { // 中
                    result = Math.min(result, cur.val - pre.val);
                }
                pre = cur;
                cur = cur.right; // 右
            }
        }
        return result;
    }
}

501.二叉搜索树中的众数(pre指针、结果集)

普通树:遍历了,用map统计频率,把频率排个序,最后取前面高频的元素的集合。
BST:中序是有序的。遍历有序数组的元素出现频率,从头遍历,那么一定是相邻两个元素作比较,然后就把出现频率最高的元素输出就可以了。
如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中。
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集。

class Solution {
    public int[] findMode(TreeNode root) {
        result = new ArrayList<>();
        countMax = 0;
        find(root, 0);
        return result.stream().mapToInt(Integer::intValue).toArray();
    }
    private List<Integer> result;
    private int countMax;
    private TreeNode pre;
    private int find(TreeNode node, int count){
        if(node==null) return count;

        count = find(node.left, count);
        if(pre!=null){
            if(pre.val == node.val){
                count++;
            }else{
                count=1;
            }
        }else{
            count++;
        }
        pre = node;
        if(count==countMax){
            result.add(node.val);
        }else if(count > countMax){
            result.clear();
            result.add(node.val);
            countMax = count;
        }
        count = find(node.right, count);
        return count;
    }
}

236. 二叉树的最近公共祖先 (回溯、后序)

返回值:返回值是TreeNode * ,那么如果遇到p或者q,就把q或者p返回,返回值不为空,就说明找到了q或者p。

  • 告诉我们是否找到节点q或者p
  • 返回最近公共节点

终止条件:树为空 || 找到了节点

递归逻辑:一定要后序遍历,才会将结果返回到父亲

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 root;
        else if(left!=null && right==null) return left;
        else if(right!=null && left==null) return right;
        else return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值