0235. Lowest Common Ancestor of a Binary Search Tree - chasel2361/leetcode GitHub Wiki
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).”
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 nodes 2 and 8 is 6.
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 nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
Example 3:
Input: root = [2,1], p = 2, q = 1
Output: 2
Constraints:
The number of nodes in the tree is in the range [2, 105].
-10^9 <= Node.val <= 10^9
All Node.val are unique.
p != q
p and q will exist in the BST.
這題的重點在於找到距離最近的"共同的父節點",我們可以從 Binary Search Tree 的特性來下手處理。
由於 BST 的子節點在儲存時會影響到儲存的位置,若子節點之值大於父節點,則子節點會位於父節點右側,若否則位於左側。
所以我們可以歸納出幾個條件:
- 若 p, q 其中一值等於當前之父節點,則當前父節點為最近的共同父節點
- 若 p, q 之值皆大於當前父節點,則共同父節點位於當前父節點之右側
- 若 p, q 之值皆小於當前父節點,則共同父節點位於當前父節點之左側
因此可以從以上三個條件來撰寫程式,一開始我用遞迴法來寫,程式碼如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
cond1 = root.val == p.val or root.val == q.val
cond2 = p.val < root.val and root.val < q.val
cond3 = p.val > root.val and root.val > q.val
if cond1 or cond2 or cond3:
return root
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
return self.lowestCommonAncestor(root.right, p, q)
這樣寫的時間複雜度是 O(N),空間複雜度也是O(N),因為最糟的狀況是都在同一邊,要走到底才會得到結果。
參考別人的寫法後才想到可以針對 p, q 先比大小再跟 root 比,這樣會比較快,程式碼如下:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or not p or not q:
return None
if (max(p.val, q.val) < root.val):
return self.lowestCommonAncestor(root.left, p, q)
elif (min(p.val, q.val) > root.val):
return self.lowestCommonAncestor(root.right, p, q)
else:
return root
另外也可以用迭代法,用移動指標的方式就可以處理
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
while root:
if max(p.val, q.val) < root.val:
root = root.left
elif min(p.val, q.val) > root.val:
root = root.right
else:
return root
return None
這樣寫的時間複雜度為O(N),空間複雜度為O(1),因為需要用到指標的空間,不會改變。
C++的寫法跟python邏輯一樣,只有語法有調整,遞迴跟迭代的時間空間複雜度也相同。
遞迴:
/**
* 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 (!root or !p or !q){
return NULL;
}
else if (max(p->val, q->val) < root->val){
return lowestCommonAncestor(root->left, p, q);
}
else if (min(p->val, q->val) > root->val){
return lowestCommonAncestor(root->right, p, q);
}
else{
return root;
}
}
};
// 迭代
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode* ptr = root;
while (ptr){
if (max(p->val, q->val) < ptr->val){
ptr = ptr->left;
}
else if (min(p->val, q->val) > ptr->val){
ptr = ptr->right;
}
else{
break;
}
}
return ptr;
}
};