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.
solutions
From a high level, we know that a valid tree satisfies the following conditions:
- There is one root, with an indegree of zero. Every other node must have an indegree of one (one parent).
- The whole tree is connected.
- No cycles.
bfs
We go through all of the children and remove them from the list of candidates for root. If we don’t end up with a single root, return early.
Else, we just BFS/DFS using the root, and return early if we ever see a node we’ve already processed (cycle exists).
Finally, ensure that the graph is fully connected (we saw every node in our traversal).
def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool:
nodes = {i for i in range(n)}
non_child_nodes = set()
for i in range(n):
if leftChild[i] > -1:
non_child_nodes.add(leftChild[i])
if rightChild[i] > -1:
non_child_nodes.add(rightChild[i])
# there doesn't exist a unique root
remaining_nodes = list(nodes - non_child_nodes)
if len(remaining_nodes) != 1:
return False
seen = set([remaining_nodes[0]])
q = deque([remaining_nodes[0]])
while q:
cur = q.popleft()
if leftChild[cur] > -1:
if leftChild[cur] in seen:
return False
q.append(leftChild[cur])
seen.add(leftChild[cur])
if rightChild[cur] > -1:
if rightChild[cur] in seen:
return False
q.append(rightChild[cur])
seen.add(rightChild[cur])
return len(seen) == nunion-find
We can determine the number of indegrees for each node using a hashmap, and then determine connectedness using union-find.
Note that we can probably handwave away the idea that if we can guarantee the indegree and connectedness property, then we can’t possibly have a cycle.
def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool:
indegrees = {node: 0 for node in range(n)}
uf = UnionFind(n)
for node in range(n):
left, right = leftChild[node], rightChild[node]
if left > -1:
indegrees[left] += 1
uf.union(node, left)
if right > -1:
indegrees[right] += 1
uf.union(node, right)
# requirement 1: one node with indegree == 0
# and every other node has indegree == 1
num_roots = 0
for indegree in indegrees.values():
if indegree > 1:
return False
if indegree == 0:
num_roots += 1
valid = num_roots == 1
# requirement 2: ensure every node is connected
for node in range(n):
uf.find(node)
valid = valid and len(set(uf.parents)) == 1
return valid