【算法系列之二叉树III】leetcode236. 二叉树的最近公共祖先

文章介绍了如何处理二叉树的几个核心问题:合并两个二叉树时节点值相加、在二叉搜索树中查找特定值的节点、验证二叉搜索树的有效性、找到二叉搜索树中的最小绝对差以及众数。同时提供了Java实现的解题思路和代码示例,包括递归和迭代方法。
摘要由CSDN通过智能技术生成

617.合并二叉树

力扣题目链接

给你两棵二叉树: root1root2

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

解决思路

  1. 如果树节点为空,则用另一颗树的节点。

Java实现

class Solution_LC617 {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if (root1 == null) {
            return root2;
        }
        if (root2 == null) {
            return root1;
        }
        int val = root1.val + root2.val;
        TreeNode root = new TreeNode(val);
        root.left = mergeTrees(root1.left, root2.left);
        root.right = mergeTrees(root1.right, root2.right);
        return root;
    }
}

700.二叉搜索树中的搜索

力扣题目地址

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null

输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

解决思路

二叉搜索树是一个有序树:

若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
  1. 当root的值>指定的值,从左子树上尝试获取;否则从右子树上获取
  2. 当root的值>指定的值,左子树上都是比root的值小的,右子树上都是比root的值大的。

Java实现

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if (root == null || root.val == val) {
            return root;
        }
        if (root.val > val) {
            return searchBST(root.left, val);
        } else {
            return searchBST(root.right, val);
        }
    }
}

98.验证二叉搜索树

力扣题目链接

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。
输入:root = [2,1,3]
输出:true

解决思路

  1. 构建新的递归函数,不断更新上限值和下限值。
  2. 中序遍历,不断比较节点
  3. 中序遍历,构成数组比较。

Java实现

递归实现

class Solution {
    public boolean isValidBST(TreeNode root) {

        return validBST(root, Long.MIN_VALUE, Long.MAX_VALUE);

    }

    private boolean validBST(TreeNode root, long lower, long upper) {
        if (root == null) {
            return true;
        }
        if (root.val <= lower || root.val >= upper) return false;
        return validBST(root.left, lower, root.val) && validBST(root.right, root.val, upper);
    }
}

中序遍历,左中右

class Solution_LC98_II {
    public boolean isValidBST(TreeNode root) {

        Stack<TreeNode> stack = new Stack<>();
        long inorder = Long.MIN_VALUE;
        TreeNode cur = root;
        while (!stack.isEmpty() || cur != null) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            if (cur.val <= inorder) {
                return false;
            }
            inorder = cur.val;
            cur = cur.right;
        }
        return true;
    }
}

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

力扣题目链接

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

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

输入:root = [4,2,6,1,3]
输出:1

解决思路

  1. 因为要获取最小值,result的初始值设置为最大。
  2. 使用中序遍历。

Java实现

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

}

501.二叉搜索树中的众数

力扣题目链接

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

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

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树
输入:root = [1,null,2,2]
输出:[2]

解题思路

  1. 使用中序遍历,去挨个遍历二叉树上的元素。如果当前元素和前一个元素一致,计数+1。
  2. 使用全局变量,记录当前元素的次数;最大的次数。

Java实现

使用递归的方式

class Solution_LC501 {
    List<Integer> answers = new ArrayList<>();
    int base, count, maxCount;

    public int[] findMode(TreeNode root) {
        dfs(root);

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

    private void dfs(TreeNode cur) {
        if (cur == null) {
            return;
        }
        dfs(cur.left);
        caluate(cur.val);
        dfs(cur.right);
    }

    private void caluate(int val) {
        if (val == base) {
            count++;
        } else {
            count = 1;
            base = val;
        }
        if (count == maxCount) {
            answers.add(val);
        }
        if (count > maxCount) {
            maxCount = count;
            answers.clear();
            answers.add(val);
        }
    }
}

使用中序迭代

class Solution_LC501_II {
    List<Integer> answers = new ArrayList<>();
    int count, maxCount;

    public int[] findMode(TreeNode root) {
        TreeNode cur = root;
        TreeNode pre = null;
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || cur != null) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            if (pre == null) {
                count = 1;
            } else if (pre.val == cur.val) {
                count++;
            } else {
                count = 1;
            }
            if (count == maxCount) {
                answers.add(cur.val);
            }
            if (count > maxCount) {
                maxCount = count;
                answers.clear();
                answers.add(cur.val);
            }

            pre = cur;
            cur = cur.right;
        }
        int[] mode = new int[answers.size()];
        for (int i = 0; i < answers.size(); ++i) {
            mode[i] = answers.get(i);
        }
        return mode;
    }
}

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

力扣题目链接

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

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

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

解题思路

  1. 如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
  2. 在子树上找到p或者q,就可以了。如果p和q分别在两个子树上都可以分别找到,则当前节点是公共祖先。

Java实现

class Solution_LC236 {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) {
            return root;
        }
        //后序遍历
        TreeNode leftNode = lowestCommonAncestor(root.left, p, q);
        TreeNode rightNode = lowestCommonAncestor(root.right, p, q);
        if (leftNode == null && rightNode == null) {
            return null;
        }
        if (leftNode == null) {
            return rightNode;
        }
        if (rightNode == null) {
            return leftNode;
        }
        return root;
    }
}

235. 二叉搜索树的最近公共祖先

力扣题目链接

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

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

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

解题思路

  1. 公共祖先的节点的值的大小必须大于等于左节点,小于等于右节点。如果当前节点的值比p和q节点的值都要大,可以在左子树上继续寻找,左子树上都是比当前节点小的数据。如果当前节点的值比p和q的节点都要小的话,在右子树上寻找。

Java实现

递归方式

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root.val > p.val && root.val > q.val) {
            return lowestCommonAncestor(root.left, p, q);
        }
        if (root.val < p.val && root.val < q.val) {
            return lowestCommonAncestor(root.right, p, q);
        }
        return root;
    }
}

非递归方式

public class Solution_LC235_II {

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while (true) {
            if (root.val > p.val && root.val > q.val) {
                root = root.left;
            } else if (root.val < p.val && root.val < q.val) {
                root = root.right;
            } else {
                break;
            }
        }
        return root;
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值