leetcode
leetcode 901 ~ 950
二叉树的堂兄弟节点

二叉树的堂兄弟节点

难度:

标签:

题目描述

在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。

如果二叉树的两个节点深度相同,但 父节点不同 ,则它们是一对堂兄弟节点

我们给出了具有唯一值的二叉树的根节点 root ,以及树中两个不同节点的值 xy

只有与值 xy 对应的节点是堂兄弟节点时,才返回 true 。否则,返回 false

 

示例 1:

输入:root = [1,2,3,4], x = 4, y = 3
输出:false

示例 2:

输入:root = [1,2,3,null,4,null,5], x = 5, y = 4
输出:true

示例 3:

输入:root = [1,2,3,null,4], x = 2, y = 3
输出:false

 

提示:

  • 二叉树的节点数介于 2 到 100 之间。
  • 每个节点的值都是唯一的、范围为 1 到 100 的整数。

 

代码结果

运行时间: 14 ms, 内存: 16.1 MB


/*
 * 思路:
 * 1. 通过DFS遍历树并使用stream API来记录每个节点的深度和父节点。
 * 2. 使用递归函数来更新深度和父节点。
 * 3. 检查两个节点的深度是否相同且父节点不同。
 */
import java.util.*;
import java.util.stream.*;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    public boolean isCousins(TreeNode root, int x, int y) {
        Map<Integer, Integer> depth = new HashMap<>();
        Map<Integer, TreeNode> parent = new HashMap<>();
        dfs(root, null, depth, parent, 0);
        return depth.get(x) == depth.get(y) && parent.get(x) != parent.get(y);
    }

    private void dfs(TreeNode node, TreeNode par, Map<Integer, Integer> depth, Map<Integer, TreeNode> parent, int d) {
        if (node == null) return;
        depth.put(node.val, d);
        parent.put(node.val, par);
        dfs(node.left, node, depth, parent, d + 1);
        dfs(node.right, node, depth, parent, d + 1);
    }
}

解释

方法:

该题解使用了深度优先搜索(DFS)来查找二叉树中的两个节点x和y。通过递归地遍历整个树,它记录下每个节点的父节点和深度。一旦找到与x或y值匹配的节点,它将记录该节点的父节点和深度。最终,如果x和y的深度相同但父节点不同,说明它们是堂兄弟节点,返回true;否则返回false。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在DFS函数中,你是如何确保一旦找到x和y节点后停止进一步的搜索?
在DFS函数中,通过使用两个非局部变量x_found和y_found来跟踪是否已找到x和y节点。一旦这两个节点都被找到,x_found和y_found将被设置为True。在每次递归调用后,会检查这两个变量,如果它们都为True,递归函数将不再进行更深层的递归调用,从而停止进一步的搜索。这是通过在每次递归进入左或右子树前后进行检查实现的。
🦆
考虑到x和y的值是唯一的,如果在递归过程中早期就找到了x和y,是否还有必要遍历整棵树?
没有必要遍历整棵树。在题解中的实现中,一旦x和y都被发现,通过检查x_found和y_found的状态,递归调用就会提前终止,从而避免了不必要的遍历。这样做提高了效率,尤其是在x和y位于树的较浅部分时。
🦆
题解中使用了`nonlocal`关键字,这主要是为了解决什么问题?
在Python中,`nonlocal`关键字用于在函数或其他作用域中修改外部作用域(非全局)的变量。题解中的`nonlocal`关键字用于允许dfs函数内部修改外层函数isCousins中定义的变量x_parent, y_parent, x_depth, y_depth, x_found, y_found。如果没有使用`nonlocal`,这些变量将被视为局部变量,从而无法更新它们的实际值。
🦆
在递归DFS中,为什么没有使用返回值来直接传递找到的节点信息,而是选择更新外部变量?
使用外部变量而不是返回值来传递找到的节点信息,可以更简洁地处理多个变量的同时更新。如果使用返回值,每次递归调用都需要返回多个值并在每个递归层级处理这些返回值,这可能会使代码更加复杂和难以理解。通过更新外部变量,可以直接在需要的地方修改和检查这些变量的状态,这使得管理状态和控制递归流程更为直接和清晰。

相关问题

二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

 

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

 

提示:

  • 树中节点数目在范围 [0, 2000]
  • -1000 <= Node.val <= 1000