LC 993. 二叉树的堂兄弟节点
题目描述
这是 LeetCode 上的 993. 二叉树的堂兄弟节点 ,难度为 简单。
在二叉树中,根节点位于深度 $0$ 处,每个深度为 $k$ 的节点的子节点位于深度 $k+1$ 处。
如果二叉树的两个节点深度相同,但 父节点不同 ,则它们是一对堂兄弟节点。
我们给出了具有唯一值的二叉树的根节点 $root$ ,以及树中两个不同节点的值 $x$ 和 $y$ 。
只有与值 $x$ 和 $y$ 对应的节点是堂兄弟节点时,才返回 true
,否则,返回 false
。
示例 1:
1 |
|
示例 2:
1 |
|
示例 3:
1 |
|
提示:
- 二叉树的节点数介于 $2$ 到 $100$ 之间。
- 每个节点的值都是唯一的、范围为 $1$ 到 $100$ 的整数。
DFS
显然,我们希望得到某个节点的「父节点」&「所在深度」,不难设计出如下「DFS 函数签名」:
1 |
|
之后按照遍历的逻辑处理即可。
需要注意的时,我们需要区分出「搜索不到」和「搜索对象为 $root$(没有 $fa$ 父节点)」两种情况。
我们约定使用 $-1$ 代指没有找到目标值 $t$,使用 $0$ 代表找到了目标值 $t$,但其不存在父节点。
Java 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Solution {
public boolean isCousins(TreeNode root, int x, int y) {
int[] xi = dfs(root, null, 0, x);
int[] yi = dfs(root, null, 0, y);
return xi[1] == yi[1] && xi[0] != yi[0];
}
int[] dfs(TreeNode root, TreeNode fa, int depth, int t) {
if (root == null) return new int[]{-1, -1}; // 使用 -1 代表为搜索不到 t
if (root.val == t) {
return new int[]{fa != null ? fa.val : 1, depth}; // 使用 1 代表搜索值 t 为 root
}
int[] l = dfs(root.left, root, depth + 1, t);
if (l[0] != -1) return l;
return dfs(root.right, root, depth + 1, t);
}
}
C++ 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Solution {
public:
bool isCousins(TreeNode* root, int x, int y) {
vector<int> xi = dfs(root, nullptr, 0, x);
vector<int> yi = dfs(root, nullptr, 0, y);
return xi[1] == yi[1] && xi[0] != yi[0];
}
vector<int> dfs(TreeNode* root, TreeNode* fa, int depth, int t) {
if (!root) return {-1, -1}; // 使用 -1 代表为搜索不到 t
if (root->val == t) {
return {fa != nullptr ? fa->val : 1, depth}; // 使用 1 代表搜索值 t 为 root
}
vector<int> l = dfs(root->left, root, depth + 1, t);
if (l[0] != -1) return l;
return dfs(root->right, root, depth + 1, t);
}
};
Python 代码:1
2
3
4
5
6
7
8
9
10
11
12
13class Solution:
def isCousins(self, root: TreeNode, x: int, y: int) -> bool:
xi = self.dfs(root, None, 0, x)
yi = self.dfs(root, None, 0, y)
return xi[1] == yi[1] and xi[0] != yi[0]
def dfs(self, root: TreeNode, fa: TreeNode, depth: int, t: int) -> list:
if not root: return [-1, -1] # 使用 -1 代表为搜索不到 t
if root.val == t:
return [fa.val if fa else 1, depth] # 使用 1 代表搜索值 t 为 root
l = self.dfs(root.left, root, depth + 1, t)
if l[0] != -1: return l
return self.dfs(root.right, root, depth + 1, t)
TypeScript 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14function dfs(root: TreeNode | null, fa: TreeNode | null, depth: number, t: number): number[] {
if (!root) return [-1, -1]; // 使用 -1 代表为搜索不到 t
if (root.val === t) {
return [fa ? fa.val : 1, depth]; // 使用 1 代表搜索值 t 为 root
}
const l = dfs(root.left, root, depth + 1, t);
if (l[0] !== -1) return l;
return dfs(root.right, root, depth + 1, t);
}
function isCousins(root: TreeNode | null, x: number, y: number): boolean {
const xi = dfs(root, null, 0, x);
const yi = dfs(root, null, 0, y);
return xi[1] === yi[1] && xi[0] !== yi[0];
};
- 时间复杂度:$O(n)$
- 空间复杂度:忽略递归开销为 $O(1)$,否则为 $O(n)$
BFS
能使用 DFS
,自然也能使用 BFS
,两者大同小异。
Java 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Solution {
public boolean isCousins(TreeNode root, int x, int y) {
int[] xi = bfs(root, x);
int[] yi = bfs(root, y);
return xi[1] == yi[1] && xi[0] != yi[0];
}
int[] bfs(TreeNode root, int t) {
Deque<Object[]> d = new ArrayDeque<>(); // 存储值为 [cur, fa, depth]
d.addLast(new Object[]{root, null, 0});
while (!d.isEmpty()) {
int size = d.size();
while (size-- > 0) {
Object[] poll = d.pollFirst();
TreeNode cur = (TreeNode)poll[0], fa = (TreeNode)poll[1];
int depth = (Integer)poll[2];
if (cur.val == t) return new int[]{fa != null ? fa.val : 0, depth};
if (cur.left != null) d.addLast(new Object[]{cur.left, cur, depth + 1});
if (cur.right != null) d.addLast(new Object[]{cur.right, cur, depth + 1});
}
}
return new int[]{-1, -1};
}
}
C++ 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Solution {
public:
bool isCousins(TreeNode* root, int x, int y) {
vector<int> xi = bfs(root, x);
vector<int> yi = bfs(root, y);
return xi[1] == yi[1] && xi[0] != yi[0];
}
vector<int> bfs(TreeNode* root, int t) {
queue<pair<TreeNode*, pair<TreeNode*, int>>> q; // 存储值为 [cur, {fa, depth}]
q.push({root, {nullptr, 0}});
while (!q.empty()) {
int size = q.size();
while (size-- > 0) {
auto poll = q.front(); q.pop();
TreeNode* cur = poll.first;
TreeNode* fa = poll.second.first;
int depth = poll.second.second;
if (cur->val == t) return {fa ? fa->val : 0, depth};
if (cur->left) q.push({cur->left, {cur, depth + 1}});
if (cur->right) q.push({cur->right, {cur, depth + 1}});
}
}
return {-1, -1};
}
};
Python 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class Solution:
def isCousins(self, root: TreeNode, x: int, y: int) -> bool:
xi = self.bfs(root, x)
yi = self.bfs(root, y)
return xi[1] == yi[1] and xi[0] != yi[0]
def bfs(self, root: TreeNode, t: int) -> list:
d = deque([(root, None, 0)]) # 存储值为 [cur, fa, depth]
while d:
size = len(d)
while size > 0:
poll = d.popleft()
cur, fa, depth = poll
if cur.val == t:
return [fa.val if fa else 0, depth]
if cur.left:
d.append((cur.left, cur, depth + 1))
if cur.right:
d.append((cur.right, cur, depth + 1))
size -= 1
return [-1, -1]
TypeScript 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function bfs(root: TreeNode | null, t: number): number[] {
const d: Array<{ cur: TreeNode | null, fa: TreeNode | null, depth: number }> = [{ cur: root, fa: null, depth: 0 }];
while (d.length > 0) {
const size = d.length;
for (let i = 0; i < size; i++) {
const { cur, fa, depth } = d.shift()!;
if (cur && cur.val === t) return fa ? [fa.val, depth] : [0, depth];
if (cur?.left) d.push({ cur: cur.left, fa: cur, depth: depth + 1 });
if (cur?.right) d.push({ cur: cur.right, fa: cur, depth: depth + 1 });
}
}
return [-1, -1];
}
function isCousins(root: TreeNode | null, x: number, y: number): boolean {
const xi = bfs(root, x);
const yi = bfs(root, y);
return xi[1] === yi[1] && xi[0] !== yi[0];
};
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.993
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!