首页 > 编程语言 >[LeetCode] 1361. Validate Binary Tree Nodes 验证二叉树

[LeetCode] 1361. Validate Binary Tree Nodes 验证二叉树

时间:2023-11-20 09:56:45浏览次数:49  
标签:Binary 结点 return int Tree rightChild leftChild 二叉树


You have n binary tree nodes numbered from 0 to n - 1 where node i has two children leftChild[i] and rightChild[i], return true if and only if all the given nodes form exactly one valid binary tree.

If node i has no left child then leftChild[i] will equal -1, similarly for the right child.

Note that the nodes have no values and that we only use the node numbers in this problem.

Example 1:

Input: n = 4, leftChild = [1,-1,3,-1], rightChild = [2,-1,-1,-1]
Output: true

Example 2:

Input: n = 4, leftChild = [1,-1,3,-1], rightChild = [2,3,-1,-1]
Output: false

Example 3:

Input: n = 2, leftChild = [1,0], rightChild = [-1,-1]
Output: false

Constraints:

  • n == leftChild.length == rightChild.length
  • 1 <= n <= 104
  • -1 <= leftChild[i], rightChild[i] <= n - 1

这道题说是给了两个数组 leftChild 和 rightChild,其中 leftChild[i] 表示结点i的左子结点,rightChild[i] 表示结点i的右子结点,若值为 -1,表示没有左子结点或着右子结点,问给定的数组是否可以组成一个有效的二叉树。对于二叉树想必大家都不陌生,来看一下题目中给的例子,例子1是一棵有效的二叉树,例子2中由于结点3有两个父结点,所以不是有效的二叉树,例子3中两个结点互为父结点了,这也不是有效的二叉树。二叉树是一种特殊的有向图,一棵有效的二叉树至少要具备这个几个特点,首先是只有一个根结点,即所有结点必须是连成一个整体的,其次是每个结点最多有两个子结点,然后每个结点最多只有一个父结点,最后就是不能出现环。

有向图有个入度 In Degree 的概念,就是某个结点被其他结点连通的个数,对于有效二叉树来说,除了根结点之外的每个结点的入度必须是1,即每个结点最多只有一个父结点,根结点的入度是0,其没有父结点。那这里就可以通过计算每个结点的入度,来快速去除一些无效的二叉树,这里用个长度为n的入度数组 inDegree,然后遍历两个数组,若左子结点不为 -1,则将其入度值自增1,此时判断一下,若入度值大于1了,说明是无效的二叉树,返回 false,对右子结点进行相同的处理。

仅判断结点的入度值是不够的,比如例子3中,每个结点的入度都是1,但不是有效二叉树,因为其没有根结点,所以接下来需要找出根结点,而且只能有一个根结点,就是说只能有一个结点的入度是0,若找到了多个,则返回 false。找到了根结点后也还不能说就是有效的二叉函数了,还得保证所有的结点都是相连的,这个通过从根结点开始遍历二叉树,统计遍历到的结点个数,若成功遍历了n个结点,才能说是有效的二叉树。遍历的方法可以用 BFS 或者 DFS,这里先用 BFS,使用队列 queue 来辅助运算,先把根结点 root 放进去,然后进行 while 循环,每次从 queue 中取出一个结点,计数器 cnt 自增1,然后看其左右子结点,若存在就加入到队列中继续循环,最后判断 cnt 是否等于n即可,参见代码如下:


解法一:

class Solution {
public:
    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
        int root = -1, cnt = 0;
        vector<int> inDegree(n);
        for (int i = 0; i < n; ++i) {
            int left = leftChild[i], right = rightChild[i];
            if (left != -1 && ++inDegree[left] > 1) return false;
            if (right != -1 && ++inDegree[right] > 1) return false;
        }
        for (int i = 0; i < n; ++i) {
            if (inDegree[i] != 0) continue;
            if (root != -1) return false;
            root = i;
        }
        if (root == -1) return false;
        queue<int> q{{root}};
        while (!q.empty()) {
            auto t = q.front(); q.pop();
            ++cnt;
            if (leftChild[t] != -1) q.push(leftChild[t]);
            if (rightChild[t] != -1) q.push(rightChild[t]);
        }
        return cnt == n;
    }
};

下面解法是用 DFS 来遍历二叉树,写起来更加简洁一些,在递归函数中首先判断若当前结点 node 为 -1,说明不存在,则返回0,否则分别对其左右子结点调用递归函数,将返回值加起来,再加上1,就是以当前结点 node 为根结点的二叉树的结点个数了,参见代码如下:


解法二:

class Solution {
public:
    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
        int root = -1, cnt = 0;
        vector<int> inDegree(n);
        for (int i = 0; i < n; ++i) {
            int left = leftChild[i], right = rightChild[i];
            if (left != -1 && ++inDegree[left] > 1) return false;
            if (right != -1 && ++inDegree[right] > 1) return false;
        }
        for (int i = 0; i < n; ++i) {
            if (inDegree[i] != 0) continue;
            if (root != -1) return false;
            root = i;
        }
        if (root == -1) return false;
        return countNodes(leftChild, rightChild, root) == n;
    }
    int countNodes(vector<int>& leftChild, vector<int>& rightChild, int node) {
        if (node == -1) return 0;
        return 1 + countNodes(leftChild, rightChild, leftChild[node]) + countNodes(leftChild, rightChild, rightChild[node]);
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1361


参考资料:

https://leetcode.com/problems/validate-binary-tree-nodes/

https://leetcode.com/problems/validate-binary-tree-nodes/solutions/517557/c-find-root-dfs/


LeetCode All in One 题目讲解汇总(持续更新中...)

标签:Binary,结点,return,int,Tree,rightChild,leftChild,二叉树
From: https://www.cnblogs.com/grandyang/p/17843256.html

相关文章

  • 【11月LeetCode组队打卡】Task2--TrieTree
    字典树Trie音同try,又称前缀树,是一颗有根树,根节点到树节点的一个路径就代表一个单词,多用于关键词检索,自动补完和拼写检查用空间换时间:借公共前缀来降低查询时间的开销根节点无内容(参考:字典树TrieTree图文详解——CSDN实现Trie题解——力扣)208.实现Trie复习一下this......
  • Java中的Set集合之TreeSet
    TreeSet:TreeSet是一个有序集合,它扩展了AbstractSet类并实现了NavigableSet接口。以下是此实现最重要方面的快速摘要:它存储唯一的元素它不保留元素的插入顺序它按升序对元素进行排序它不是线程安全的在该实现中,对象根据其自然顺序以升序排序和存储。该TreeSet中使用的是一......
  • 构建二叉树
    构建二叉树本文图文并茂讲解从前序遍历、中序续遍历构建二叉树或者从后序遍历、中序续遍历又或者从前序遍历、后序续遍历构建二叉树的原理,比附上相关的习题。图解链接:飞书图解链接......
  • 变长子网划分问题的二叉树解法
    计网的变长子网划分、计组的变长操作码划分、数据结构的哈夫曼编码,都是前缀编码的本质(变长操作码的二叉树解法我还在琢磨中)【二叉树解法】每条从叶结点到根节点的路径上有且只有一个被分配的结点:【例】现将一个IP网络划分成4个子网,若其中一个子网是172.16.1.128/26,则下列网络中......
  • 数据结构之二叉树的遍历2(java)
    一:概述二叉树的深度遍历3种方式:前序遍历、中序遍历、后序遍历。下面是具体的这三种方式的遍历代码。二:具体概述用递归的方式实现前序遍历、中序遍历、后序遍历。publicclassTreeNodeTraveral{/***构建二叉树**@paraminputList输入序列*/......
  • etree和协程爬明朝那些事、
    1、etree和协程爬明朝那些事importrequestsfromlxmlimportetreeimportasyncioimportaiohttpimportaiofilesimportos#1.拿到主页面的源代码(不需要异步)#2.拿到页面源代码之后.需要解析出<卷名>,<章节,href>headers={"user-agent":"Mozilla/5.0(Windows......
  • 代码随想训练营第三十七天(Python)| 738.单调递增的数字、968.监控二叉树
    738.单调递增的数字classSolution:defmonotoneIncreasingDigits(self,n:int)->int:#主要思路当前数字比前面数字小时。前面数字-1,当前数字变2为9str_n=str(n)foriinrange(len(str_n)-1,0,-1):ifstr_n[i]<str_n[......
  • P4115 Qtree4 题解
    P4115看到单点修改,求全局白色的最远距离,可以使用点分树。考虑维护这棵点分树,想想树的直径的dp求法:\(f_u=\max\{f_v+w(u,v)\}\),答案为\(\max(f_v+f_{v'})(v,v'\in\{\text{son}_u\})\),\(\{\text{son}_i\}\)表示\(i\)的孩子集合。这时候维护就十分简单了,对于每个点都......
  • (javascript)将ztree树结构的数据转成二维数组
    ztree树结构的数据结构如下:[{"id":3990,"name":"泡沫灭火","iconShow":false,"children":[{"id":8616,......
  • 了解tree shaking
    前言前端在做性能优化的时候,其中一种有效的方式就是减少包体积的大小。而减少包体积大小的其中一种有效的方式就是tree-shaking,翻译成中文就是摇树。这个词非常形象,当果树结果后,如果用力摇树,那些成熟了但是还挂在树上的果子就会掉下来,减轻树的负担,因为果子已经成熟了,没有必要在......