二叉树题目:二叉树的堂兄弟结点

题目

标题和出处

标题:二叉树的堂兄弟结点

出处:993. 二叉树的堂兄弟结点

难度

3 级

题目描述

要求

给你具有唯一值的二叉树的根结点 root \texttt{root} root,以及树中两个不同结点的值 x \texttt{x} x y \texttt{y} y,如果值 x \texttt{x} x y \texttt{y} y 对应的结点是堂兄弟结点,返回 true \texttt{true} true,否则返回 false \texttt{false} false

如果二叉树的两个结点深度相同且父结点不同,则它们是堂兄弟结点。

在二叉树中,根结点位于深度 0 \texttt{0} 0 处,每个深度为 k \texttt{k} k 的结点的子结点位于深度 k   +   1 \texttt{k + 1} k + 1 处。

示例

示例 1:

示例 1

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

示例 2:

示例 2

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

示例 3:

示例 3

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

数据范围

  • 树中结点数目在范围 [2,   100] \texttt{[2, 100]} [2, 100]
  • 1 ≤ Node.val ≤ 100 \texttt{1} \le \texttt{Node.val} \le \texttt{100} 1Node.val100
  • 每个结点的值都唯一
  • x ≠ y \texttt{x} \ne \texttt{y} x=y
  • x \texttt{x} x y \texttt{y} y 是树中存在的结点值

解法一

思路和算法

根据堂兄弟结点的定义,两个结点是堂兄弟结点等价于两个结点的深度相同且父结点不同。为了判断两个结点是否是堂兄弟结点,需要得到两个结点的深度和父结点。

由于二叉树中每个结点的值都唯一,并且给定的两个结点值都是二叉树中存在的结点值,因此可以根据给定的两个结点值唯一地确定两个结点。可以使用深度优先搜索遍历二叉树中的全部结点,遍历过程中维护每个结点的深度和父结点信息,当两个结点都找到时即可停止遍历。

遍历结束之后,即可判断两个结点是否是堂兄弟结点。如果两个结点深度相同且父结点不同,则是堂兄弟结点,否则不是堂兄弟结点。

代码

class Solution {
    int x, y;
    int xDepth, yDepth;
    TreeNode xParent, yParent;

    public boolean isCousins(TreeNode root, int x, int y) {
        this.x = x;
        this.y = y;
        this.xDepth = -1;
        this.yDepth = -1;
        this.xParent = null;
        this.yParent = null;
        findNodes(root, 0, null);
        return xDepth == yDepth && xParent != yParent;
    }

    public void findNodes(TreeNode node, int depth, TreeNode parent) {
        if (xDepth >= 0 && yDepth >= 0) {
            return;
        }
        if (node.val == x) {
            xDepth = depth;
            xParent = parent;
        } else if (node.val == y) {
            yDepth = depth;
            yParent = parent;
        }
        if (node.left != null) {
            findNodes(node.left, depth + 1, node);
        }
        if (node.right != null) {
            findNodes(node.right, depth + 1, node);
        }
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点最多被访问一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉树的高度,最差情况下二叉树的高度是 O ( n ) O(n) O(n)

解法二

思路和算法

也可以使用广度优先搜索遍历二叉树并寻找两个结点。

广度优先搜索需要使用队列存储待访问的结点,初始时将根结点入队列。遍历过程中,每次将一个结点出队列,然后将该结点的非空子结点入队列,直到队列为空时遍历结束。

由于判断堂兄弟结点需要维护每个结点的深度,因此在广度优先搜索的过程中需要维护深度的信息。为了维护深度的信息,需要确保每一轮访问的结点为同一层的全部结点,做法是每一轮访问结点之前需要首先得到队列内的元素个数,此时队列内的元素为同一层的全部结点,然后访问这些结点,并将这些结点的非空子结点入队列。上述做法可以确保每一轮访问的结点为同一层的全部结点。

由于判断堂兄弟结点需要维护每个结点的父结点,因此在遍历过程中需要对访问到的每个结点的子结点判断是否是待寻找的结点。如果访问到的结点的一个子结点是其中一个待寻找的结点,则当前结点即为其中一个待寻找的结点的父结点。

和深度优先搜索一样,广度优先搜索不需要遍历二叉树中的所有结点,当两个结点都找到时即可停止遍历。

遍历结束之后,即可判断两个结点是否是堂兄弟结点。如果两个结点深度相同且父结点不同,则是堂兄弟结点,否则不是堂兄弟结点。

代码

class Solution {
    public boolean isCousins(TreeNode root, int x, int y) {
        int xDepth = -1, yDepth = -1;
        TreeNode xParent = null, yParent = null;
        int depth = 0;
        Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
        queue.offer(root);
        while (!queue.isEmpty() && (xDepth < 0 || yDepth < 0)) {
            depth++;
            int size = queue.size();
            for (int i = 0; i < size && (xDepth < 0 || yDepth < 0); i++) {
                TreeNode node = queue.poll();
                TreeNode left = node.left, right = node.right;
                if (left != null) {
                    if (left.val == x) {
                        xDepth = depth;
                        xParent = node;
                    } else if (left.val == y) {
                        yDepth = depth;
                        yParent = node;
                    }
                    queue.offer(left);
                }
                if (right != null) {
                    if (right.val == x) {
                        xDepth = depth;
                        xParent = node;
                    } else if (right.val == y) {
                        yDepth = depth;
                        yParent = node;
                    }
                    queue.offer(right);
                }
            }
        }
        return xDepth == yDepth && xParent != yParent;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点最多被访问一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是队列空间,队列内元素个数不超过 n n n

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值