1 问题
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。最近祖先的深度尽可能大(高度尽可能小)
2 思路
与二叉树的公共祖先类似https://blog.youkuaiyun.com/qq_44776065/article/details/140675872,一般的方法也适用于特殊。
但是考虑到二叉搜索树的特性,即中序遍历二叉搜索树是一个递增序列,能否更加快速的找到答案呢?
在二叉搜索树的公共祖先中,使用后序遍历的方式在左右子树中查找,并扫描了整个树的节点,能不能扫描部分节点,以节省时间?
【考虑到二叉搜索树的性质】:如果一个节点第一次出现在p和q的区间(q.val < q.val)内,则其就是二叉搜索树的最近公共祖先。因此只需要进行区间的判断即可。
为什么是第一次出现在区间内就是呢,想象一下,上图终[1,3, 5, 6, 8, 9],其中找1和9的最近公共祖先,自上而下的遍历,5是第一次出现在区间内,无论向左还是向右,这些点是第二次出现在区间内,则会跑到另一个子树上,因此不能满足寻找公共祖先的条件。
因此,第一次出现在区间的点就是最近公共祖先节点
因此可以根据区间进行选择【更加类似前序遍历】
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root != null) {
// 进行区间判断
if (root.val > p.val && root.val > q.val) { // p q 没有大小关系,都要判断
TreeNode left = lowestCommonAncestor(root.left, p, q);
if (left != null) return left; // 找到后就返回
}
if (root.val < p.val && root.val < q.val) {
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (right != null) return right;
}
// 第一次在区间内的点
if (root.val >= p.val || root.val >= q.val || root.val <= p.val || root.val <= q.val)
return root;
}
return null;
}
}
Note:
- 在区间内不要忘记了等于号,也可以省略,可以把最后当成else的情况
- 根据区间选择性递归,相当于剪枝,降低了时间复杂度【相比于一般二叉树找最近公共祖先】
ACM输入输出
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode () {}
TreeNode (int val) {this.val = val; }
}
// Solution
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Solution solution = new Solution();
while (in.hasNext()) {
String[] strNums = in.nextLine().split(" ");
List<TreeNode> nodes = new LinkedList<>();
for (String strNum: strNums) {
if (!strNum.isEmpty()) {
if (strNum.equals("null")) {
nodes.add(null);
} else {
nodes.add(new TreeNode(Integer.parseInt(strNum)));
}
}
}
TreeNode root = constructTree(nodes);
int num1 = Integer.parseInt(in.nextLine());
int num2 = Integer.parseInt(in.nextLine());
TreeNode p = new TreeNode(num1);
TreeNode q = new TreeNode(num2);
TreeNode r = solution.lowestCommonAncestor(root, p, q);
if (r != null) System.out.println(r.val);
else System.out.println("not found!");
}
}
public static TreeNode constructTree(List<TreeNode> nodes) {
if (!nodes.isEmpty()) {
TreeNode node = nodes.remove(0);
if (node != null) {
node.left = constructTree(nodes);
node.right = constructTree(nodes);
}
return node;
}
return null;
}
}
/*
test case:
6 2 0 null null 4 3 null null 5 null null 8 7 null null 9
2
8
r = [6]
*/