Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add solutions to lc problem: No.0236 #2328

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add solutions to lc problem: No.0236
No.0236.Lowest Common Ancestor of a Binary Tree
  • Loading branch information
yanglbme committed Feb 9, 2024
commit bfe08aa541e23b4154e473cc9c4da3cc7454b64d
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,13 @@

### 方法一:递归

根据“**最近公共祖先**”的定义,若 root 是 p, q 的最近公共祖先 ,则只可能为以下情况之一
我们递归遍历二叉树

- 如果 p 和 q 分别是 root 的左右节点,那么 root 就是我们要找的最近公共祖先;
- 如果 p 和 q 都是 root 的左节点,那么返回 `lowestCommonAncestor(root.left, p, q)`;
- 如果 p 和 q 都是 root 的右节点,那么返回 `lowestCommonAncestor(root.right, p, q)`。
如果当前节点为空或者等于 $p$ 或者 $q$,则返回当前节点;

**边界条件讨论**:
否则,我们递归遍历左右子树,将返回的结果分别记为 $left$ 和 $right$。如果 $left$ 和 $right$ 都不为空,则说明 $p$ 和 $q$ 分别在左右子树中,因此当前节点即为最近公共祖先;如果 $left$ 和 $right$ 中只有一个不为空,返回不为空的那个。

- 如果 root 为 null,则说明我们已经找到最底了,返回 null 表示没找到;
- 如果 root 与 p 相等或者与 q 相等,则返回 root;
- 如果左子树没找到,递归函数返回 null,证明 p 和 q 同在 root 的右侧,那么最终的公共祖先就是右子树找到的结点;
- 如果右子树没找到,递归函数返回 null,证明 p 和 q 同在 root 的左侧,那么最终的公共祖先就是左子树找到的结点。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为二叉树节点个数。

<!-- tabs:start -->

Expand All @@ -77,9 +72,9 @@

class Solution:
def lowestCommonAncestor(
self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'
) -> 'TreeNode':
if root is None or root == p or root == q:
self, root: "TreeNode", p: "TreeNode", q: "TreeNode"
) -> "TreeNode":
if root in (None, p, q):
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
Expand All @@ -98,12 +93,15 @@ class Solution:
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left == null) return right;
if (right == null) return left;
return root;
if (root == null || root == p || root == q) {
return root;
}
var left = lowestCommonAncestor(root.left, p, q);
var right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
return left == null ? right : left;
}
}
```
Expand All @@ -121,10 +119,14 @@ class Solution {
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (!root || root == p || root == q) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) return root;
if (root == nullptr || root == p || root == q) {
return root;
}
auto left = lowestCommonAncestor(root->left, p, q);
auto right = lowestCommonAncestor(root->right, p, q);
if (left && right) {
return root;
}
return left ? left : right;
}
};
Expand All @@ -145,13 +147,13 @@ func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
}
left := lowestCommonAncestor(root.Left, p, q)
right := lowestCommonAncestor(root.Right, p, q)
if left == nil {
return right
if left != nil && right != nil {
return root
}
if right == nil {
if left != nil {
return left
}
return root
return right
}
```

Expand All @@ -175,21 +177,12 @@ function lowestCommonAncestor(
p: TreeNode | null,
q: TreeNode | null,
): TreeNode | null {
const find = (root: TreeNode | null) => {
if (root == null || root == p || root == q) {
return root;
}
const left = find(root.left);
const right = find(root.right);
if (left != null && right != null) {
return root;
}
if (left != null) {
return left;
}
return right;
};
return find(root);
if (!root || root === p || root === q) {
return root;
}
const left = lowestCommonAncestor(root.left, p, q);
const right = lowestCommonAncestor(root.right, p, q);
return left && right ? root : left || right;
}
```

Expand All @@ -215,31 +208,31 @@ function lowestCommonAncestor(
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {
fn find(
root: &Option<Rc<RefCell<TreeNode>>>,
p: &Option<Rc<RefCell<TreeNode>>>,
q: &Option<Rc<RefCell<TreeNode>>>
) -> Option<Rc<RefCell<TreeNode>>> {
if root.is_none() || root == p || root == q {
return root.clone();
}
let node = root.as_ref().unwrap().borrow();
let left = Self::find(&node.left, p, q);
let right = Self::find(&node.right, p, q);
match (left.is_some(), right.is_some()) {
(true, false) => left,
(false, true) => right,
(false, false) => None,
(true, true) => root.clone(),
}
}

pub fn lowest_common_ancestor(
root: Option<Rc<RefCell<TreeNode>>>,
p: Option<Rc<RefCell<TreeNode>>>,
q: Option<Rc<RefCell<TreeNode>>>
) -> Option<Rc<RefCell<TreeNode>>> {
Self::find(&root, &p, &q)
if root.is_none() || root == p || root == q {
return root;
}
let left = Self::lowest_common_ancestor(
root.as_ref().unwrap().borrow().left.clone(),
p.clone(),
q.clone()
);
let right = Self::lowest_common_ancestor(
root.as_ref().unwrap().borrow().right.clone(),
p.clone(),
q.clone()
);
if left.is_some() && right.is_some() {
return root;
}
if left.is_none() {
return right;
}
return left;
}
}
```
Expand All @@ -259,12 +252,12 @@ impl Solution {
* @return {TreeNode}
*/
var lowestCommonAncestor = function (root, p, q) {
if (!root || root == p || root == q) return root;
if (!root || root === p || root === q) {
return root;
}
const left = lowestCommonAncestor(root.left, p, q);
const right = lowestCommonAncestor(root.right, p, q);
if (!left) return right;
if (!right) return left;
return root;
return left && right ? root : left || right;
};
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@

## Solutions

### Solution 1
### Solution 1: Recursion

We recursively traverse the binary tree:

If the current node is null or equals to $p$ or $q$, then we return the current node;

Otherwise, we recursively traverse the left and right subtrees, and record the returned results as $left$ and $right$. If both $left$ and $right$ are not null, it means that $p$ and $q$ are in the left and right subtrees respectively, so the current node is the nearest common ancestor; If only one of $left$ and $right$ is not null, we return the one that is not null.

The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree.

<!-- tabs:start -->

Expand All @@ -60,9 +68,9 @@

class Solution:
def lowestCommonAncestor(
self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'
) -> 'TreeNode':
if root is None or root == p or root == q:
self, root: "TreeNode", p: "TreeNode", q: "TreeNode"
) -> "TreeNode":
if root in (None, p, q):
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
Expand All @@ -81,12 +89,15 @@ class Solution:
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left == null) return right;
if (right == null) return left;
return root;
if (root == null || root == p || root == q) {
return root;
}
var left = lowestCommonAncestor(root.left, p, q);
var right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
return left == null ? right : left;
}
}
```
Expand All @@ -104,10 +115,14 @@ class Solution {
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (!root || root == p || root == q) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) return root;
if (root == nullptr || root == p || root == q) {
return root;
}
auto left = lowestCommonAncestor(root->left, p, q);
auto right = lowestCommonAncestor(root->right, p, q);
if (left && right) {
return root;
}
return left ? left : right;
}
};
Expand All @@ -128,13 +143,13 @@ func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
}
left := lowestCommonAncestor(root.Left, p, q)
right := lowestCommonAncestor(root.Right, p, q)
if left == nil {
return right
if left != nil && right != nil {
return root
}
if right == nil {
if left != nil {
return left
}
return root
return right
}
```

Expand All @@ -158,21 +173,12 @@ function lowestCommonAncestor(
p: TreeNode | null,
q: TreeNode | null,
): TreeNode | null {
const find = (root: TreeNode | null) => {
if (root == null || root == p || root == q) {
return root;
}
const left = find(root.left);
const right = find(root.right);
if (left != null && right != null) {
return root;
}
if (left != null) {
return left;
}
return right;
};
return find(root);
if (!root || root === p || root === q) {
return root;
}
const left = lowestCommonAncestor(root.left, p, q);
const right = lowestCommonAncestor(root.right, p, q);
return left && right ? root : left || right;
}
```

Expand All @@ -198,31 +204,31 @@ function lowestCommonAncestor(
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {
fn find(
root: &Option<Rc<RefCell<TreeNode>>>,
p: &Option<Rc<RefCell<TreeNode>>>,
q: &Option<Rc<RefCell<TreeNode>>>
) -> Option<Rc<RefCell<TreeNode>>> {
if root.is_none() || root == p || root == q {
return root.clone();
}
let node = root.as_ref().unwrap().borrow();
let left = Self::find(&node.left, p, q);
let right = Self::find(&node.right, p, q);
match (left.is_some(), right.is_some()) {
(true, false) => left,
(false, true) => right,
(false, false) => None,
(true, true) => root.clone(),
}
}

pub fn lowest_common_ancestor(
root: Option<Rc<RefCell<TreeNode>>>,
p: Option<Rc<RefCell<TreeNode>>>,
q: Option<Rc<RefCell<TreeNode>>>
) -> Option<Rc<RefCell<TreeNode>>> {
Self::find(&root, &p, &q)
if root.is_none() || root == p || root == q {
return root;
}
let left = Self::lowest_common_ancestor(
root.as_ref().unwrap().borrow().left.clone(),
p.clone(),
q.clone()
);
let right = Self::lowest_common_ancestor(
root.as_ref().unwrap().borrow().right.clone(),
p.clone(),
q.clone()
);
if left.is_some() && right.is_some() {
return root;
}
if left.is_none() {
return right;
}
return left;
}
}
```
Expand All @@ -242,12 +248,12 @@ impl Solution {
* @return {TreeNode}
*/
var lowestCommonAncestor = function (root, p, q) {
if (!root || root == p || root == q) return root;
if (!root || root === p || root === q) {
return root;
}
const left = lowestCommonAncestor(root.left, p, q);
const right = lowestCommonAncestor(root.right, p, q);
if (!left) return right;
if (!right) return left;
return root;
return left && right ? root : left || right;
};
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (!root || root == p || root == q) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) return root;
if (root == nullptr || root == p || root == q) {
return root;
}
auto left = lowestCommonAncestor(root->left, p, q);
auto right = lowestCommonAncestor(root->right, p, q);
if (left && right) {
return root;
}
return left ? left : right;
}
};
Loading
Loading