刷题日记18 | 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

71 阅读1分钟

刷题日记18

今天依然是二叉搜索树,好吧已经连续5天刷二叉树了,是时候总结一下二叉树的题型了。

二叉搜索树的主要特点就是有序,可以看成是一个有序的数组,这样求最值,最小差值都会很容易。

530. 二叉搜索树的最小绝对差

中序遍历迭代法

class Solution {
    public int getMinimumDifference(TreeNode root) {
        Stack<TreeNode> s = new Stack<>();
        TreeNode pre = null;
        int diff = Integer.MAX_VALUE;
        s.push(root);
        while(!s.isEmpty()){
            TreeNode node = s.peek();
            if(node != null){
                s.pop();
                if(node.right != null) s.push(node.right);
                s.push(node);
                s.push(null);
                if(node.left != null) s.push(node.left);
            }else{
                s.pop();
                node = s.pop();
                if(pre != null) diff = Math.min(diff, Math.abs(node.val - pre.val));
                pre = node;
            }
        }
        return diff;
    }
}

中序遍历递归法

class Solution {
    public int diff = Integer.MAX_VALUE;
    public TreeNode pre = null;
    public int getMinimumDifference(TreeNode root) {
        inorder(root);
        return diff;
    }
    public void inorder(TreeNode root){
        if(root == null) return;
        inorder(root.left);
        if(pre != null) diff = Math.min(diff, Math.abs(pre.val - root.val));
        pre = root;
        inorder(root.right);
    }
}

501. 二叉搜索树中的众数

一般来讲,求众数这种需要计算频率的问题,都会使用哈希表来记录频率,如下面这种算法。但这道题是二叉搜索树,一个有序的数组里,如果会出现众数,那他们一定是连续的,其实不需要一个哈希表,只需要记录前一个节点。

中序遍历,哈希表算法

class Solution {
    public LinkedList<Integer> res = new LinkedList<>();
    public Map<Integer, Integer> map = new HashMap<>();
    public int[] findMode(TreeNode root) {
        inorder(root);
        return res.stream().mapToInt(Integer::valueOf).toArray();
    }
    public void inorder(TreeNode root){
        if(root == null) return;
        inorder(root.left);
        map.put(root.val, map.getOrDefault(root.val, 0) + 1);
        if(res.size() != 0){
            if(map.get(root.val) > map.get(res.get(0))){
                LinkedList<Integer> result = new LinkedList<>();
                result.add(root.val);
                res = result;
            }
            else if(root.val != res.get(0) && map.get(root.val) == map.get(res.get(0))){
                res.add(root.val);
            }
        }else{
            res.add(root.val);
        }
        inorder(root.right);
    }
}

中序遍历,只记录前一个节点

class Solution {
    public LinkedList<Integer> res = new LinkedList<>();
    public TreeNode pre = null;
    public int count = 0;
    public int maxCount = 0;;
    public int[] findMode(TreeNode root) {
        inorder(root);
        return res.stream().mapToInt(Integer::valueOf).toArray();
    }
    public void inorder(TreeNode root){
        if(root == null) return;
        inorder(root.left);

        if(pre == null || root.val != pre.val){
            count = 1;
        }else{
            count++;
        }
        if(count > maxCount){
            res.clear();
            res.add(root.val);
            maxCount = count;
        }else if(count == maxCount){
            res.add(root.val);
        }
        pre = root;

        inorder(root.right);
    }
}

236. 二叉树的最近公共祖先

最开始的思路肯定是要后序遍历,因为这道题要进行从下至上的遍历,只有后序遍历能从下至上查找。

那怎么才算找到了最近公共祖先呢?也就是说有哪些情况呢?

根据以上定义,若 root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:

  • p 和 q 在 root 的子树中,且分列 root 的 异侧(即分别在左、右子树中)
  • p = root,且 q 在 root 的左或右子树中
  • q = root,且 p 在 root 的左或右子树中

这道题很难想出递归的终止条件,主要还是因为,一个节点自己也是自己的祖先。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == q || root == p) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left == null && right == null) return null;
        if(left == null && right != null) return right;
        if(left != null && right == null) return left;
        return root;
    }
}