算法训练营 day21 二叉树 二叉搜索树的最小绝对差 二叉搜索树中的众数 二叉树的最近公共祖先

算法训练营 day21 二叉树 二叉搜索树的最小绝对差 二叉搜索树中的众数 二叉树的最近公共祖先

二叉搜索树的最小绝对差

530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值

差值是一个正数,其数值等于两值之差的绝对值。

递归法

注意是二叉搜索树,二叉搜索树可是有序的。

遇到在二叉搜索树上求什么最值啊,差值之类的,就把它想成在一个有序数组上求最值,求差值,这样就简单多了。在一个有序数组上求两个数最小差值。

需要用一个pre节点记录一下cur节点的前一个节点。

在这里插入图片描述

//一般解法
class Solution {
    ArrayList<Integer> arr = new ArrayList<>();

    public int getMinimumDifference(TreeNode root) {
        traversal(root);
        if (arr.size() < 2) return 0;
        int result = Integer.MAX_VALUE;
        for (int i = 1; i < arr.size(); i++) {
            result = Math.min(result, arr.get(i) - arr.get(i - 1));
        }
        return result;
    }

    private void traversal(TreeNode root) {
        if (root == null) return;
        traversal(root.left);
        arr.add(root.val);
        traversal(root.right);
    }
}

//双指针递归
class Solution {
    int result = Integer.MAX_VALUE;
    TreeNode pre = null;

    public int getMinimumDifference(TreeNode root) {
        traversal(root);
        return result;
    }
    private void traversal(TreeNode cur) {
        if (cur == null) return;
        traversal(cur.left);
        if (pre != null) {
            result = Math.min(result, cur.val - pre.val);
        }
        pre = cur;
        traversal(cur.right);
    }
}

迭代法

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

二叉搜索树中的众数

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

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

结点左子树中所含节点的值 小于等于 当前节点的值
结点右子树中所含节点的值 大于等于 当前节点的值
左子树和右子树都是二叉搜索树

既然是搜索树,它中序遍历就是有序的

遍历有序数组的元素出现频率,从头遍历,那么一定是相邻两个元素作比较,然后就把出现频率最高的元素输出就可以了。

递归法

class Solution {
    ArrayList<Integer> resultList = new ArrayList<>();;
    TreeNode pre = null;
    int maxCount = 0;
    int count = 0;

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

    private void traversal(TreeNode cur) {
        if (cur == null) return;

        traversal(cur.left);
        if (pre == null) count = 1;
        else if (pre.val == cur.val) count++;
        else count = 1;
        pre = cur;
        if (count == maxCount) resultList.add(cur.val);
        if (count > maxCount) {
            maxCount = count;
            resultList.clear();
            resultList.add(cur.val);
        }
        traversal(cur.right);
    }
}

迭代法

class Solution {
    public int[] findMode(TreeNode root) {
        ArrayList<Integer> resultList = new ArrayList<>();
        TreeNode pre = null;
        int maxCount = 0;
        int count = 0;
        Stack<TreeNode> st = new Stack<>();
        if (root == null) return new int[0];
        st.push(root);


        while (!st.isEmpty()) {
            TreeNode node = st.pop();
            if (node != null) {
                if (node.right != null) st.push(node.right);
                st.push(node);
                st.push(null);
                if (node.left != null) st.push(node.left);
            } else {
                node = st.pop();
                if (pre == null || pre.val != node.val) count = 1;
                else count++;
                pre = node;
                if (count == maxCount) resultList.add(node.val);
                if (count > maxCount) {
                    maxCount = count;
                    resultList.clear();
                    resultList.add(node.val);
                }
            }
        }

        int[] result = new int[resultList.size()];
        for (int i = 0; i < resultList.size(); i++) {
            result[i] = resultList.get(i);
        }
        return result;
    }
}

二叉树的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。 即情况一:

在这里插入图片描述

二叉树节点数值是不重复的,而且一定存在 q 和 p

但是很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q§。 情况二:

在这里插入图片描述

递归三部曲:

  • 确定递归函数返回值以及参数

需要递归函数返回值,来告诉我们是否找到节点q或者p,那么返回值为bool类型就可以了。

但我们还要返回最近公共节点,可以利用上题目中返回值是TreeNode * ,那么如果遇到p或者q,就把q或者p返回,返回值不为空,就说明找到了q或者p。

  • 确定终止条件

遇到空的话,因为树都是空了,所以返回空。

那么我们来说一说,如果 root == q,或者 root == p,说明找到 q p ,则将其返回,这个返回值,后面在中节点的处理过程中会用到,

  • 确定单层递归逻辑

值得注意的是 本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。

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

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return null;
        if (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 root;
        
        if (left==null&&right!=null) return right;
        else if (left!=null&&right==null) return left;
        else return null;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还是选择了面包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值