题目:
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Given binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5]
Example 1:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 Output: 6 Explanation: The LCA of nodes2
and8
is6
.
Example 2:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 Output: 2 Explanation: The LCA of nodes2
and4
is2
, since a node can be a descendant of itself according to the LCA definition.
Note:
- All of the nodes' values will be unique.
- p and q are different and both values will exist in the BST.
这道题乍一看觉得好难,一点思路都没有,但是看了解答以后真的豁然开朗。需要利用二叉搜索树的性质,一个节点的左子节点永远比这个节点小,而右子节点永远比这个节点大。如果需要找到两个节点的最低公共祖先,那么就是从上往下遍历的过程中最后一个满足p和q两个节点分别在它的左右的情况,也就是p和q分别比当前节点的值要小或者大。如果p、q同时在一个节点的同一侧的话,就沿着这一侧的子节点继续往下找。但是注意到,还有一种情况是p和q之中有一个节点是另一个节点的祖先节点,如下图中的第二种和第三种:
在这种情况下,我们依旧可以通过前面的判断条件来判断是否找到了这个节点。因为如果p和q任意一个节点就是当前的根节点的话,我们就直接返回当前的根节点就行,也就是下面代码中的else。代码时间复杂度在最坏的情况下(如果这棵树非常不平衡并且p和q都处在很深的地方),这时候几乎要遍历所有的节点,就是O(n),而如果是平衡二叉树则只需要O(logn),运行时间36ms,79.9%,空间由于用到了递归栈就是复杂度O(n)(万一树不平衡那它的深度就是n了),25.6M,100%。(为了看这个百分比我又提交了一次,发现这次运行了40ms,只有50.7%,空间25.7M,100%)代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if ((p->val < root->val) && (q->val < root->val)) {
return lowestCommonAncestor(root->left, p, q);
}
else if ((p->val > root->val) && (q->val > root->val)) {
return lowestCommonAncestor(root->right, p, q);
}
else {
return root;
}
}
};
2020.10.06 Java:
Runtime: 4 ms, faster than 66.18% of Java online submissions for Lowest Common Ancestor of a Binary Search Tree.
Memory Usage: 39.7 MB, less than 96.73% of Java online submissions for Lowest Common Ancestor of a Binary Search Tree.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (p.val < root.val && q.val < root.val) {
return lowestCommonAncestor(root.left, p, q);
}
if (p.val > root.val && q.val > root.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
另外一种是迭代的写法,思路和递归一毛一样,并且写起来也很方便,不需要用到什么栈啊队列啊之类的(好像是因为不用backtrace?),时间40ms,50.74%,空间25.5M,100%:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while (root) {
if ((p->val < root->val) && (q->val < root->val)) {
root = root->left;
}
else if ((p->val > root->val) && (q->val > root->val)) {
root = root->right;
}
else {
return root;
}
}
return root;
}
};
2020.10.12 Java:
Runtime: 3 ms, faster than 100.00% of Java online submissions for Lowest Common Ancestor of a Binary Search Tree.
Memory Usage: 39.8 MB, less than 7.98% of Java online submissions for Lowest Common Ancestor of a Binary Search Tree.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while (root != null) {
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 {
return root;
}
}
return root;
}
}