二叉树上有
n
个节点,按从0
到n - 1
编号,其中节点i
的两个子节点分别是leftChild[i]
和rightChild[i]
。只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时,返回
true
;否则返回false
。如果节点
i
没有左子节点,那么leftChild[i]
就等于-1
。右子节点也符合该规则。注意:节点没有值,本问题中仅仅使用节点编号。
输入:n = 4, leftChild = [1,-1,3,-1], rightChild = [2,-1,-1,-1] 输出:true
/**
* @param {number} n
* @param {number[]} leftChild
* @param {number[]} rightChild
* @return {boolean}
*/
var validateBinaryTreeNodes = function (n, leftChild, rightChild) {
//统计边数
let edges = 0;
//统计入度
let nodeIn = new Array(n).fill(0);
//统计出度
let nodeOut = new Array(n).fill(0);
for (let i = 0; i < n; i++) {
if (leftChild[i] !== -1) {
nodeIn[leftChild[i]]++;
nodeOut[i]++;
edges++;
}
if (rightChild[i] !== -1) {
nodeIn[rightChild[i]]++;
nodeOut[i]++;
edges++;
}
};
//如果不满足n个结点仅有n-1条边,那么说明该图不是二叉树。
if (edges !== n - 1) {
return false;
}
/**
* 拓扑排序,判断图是否有环
* 求出图中所有结点的出入度。
* 将所有入度 === 0 的结点入队。
* 当队列不空时,弹出队首元素,把与队首元素的左右子节点的入度减一。
* 如果存在某个子节点的入度变为0,则将该结点入队。
* 循环结束时判断已经访问的结点数,全部访问说明,图无环;存在没有访问到的结点,则有环。
*/
let queue = [];
let visited = new Array(n).fill(false);
for (let i = 0; i < nodeIn.length; i++) {
if (nodeIn[i] === 0)
queue.push(i);
}
while (queue.length) {
let node = queue.shift();
visited[node] = true;
if (leftChild[node] !== -1 && nodeIn[leftChild[node]] === 1) {
nodeIn[leftChild[node]]--;
queue.push(leftChild[node]);
}
if (rightChild[node] !== -1 && nodeIn[rightChild[node]] == 1) {
nodeIn[rightChild[node]]--;
queue.push(rightChild[node]);
}
}
// 判断是否全部访问
for (let i = 0; i < n; i++) {
if (visited[i] === false)
return false;
}
return true
};