331、验证二叉树的前序序列化
序列化二叉树的一种方法是使用 前序遍历 。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #
。
给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。
保证 每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 ‘#’ 。
你可以认为输入格式总是有效的
- 例如它永远不会包含两个连续的逗号,比如 “1,3” 。
注意:不允许重建树。
示例1:
输入: preorder = "9,3,4,#,#,1,#,#,2,#,6,#,#"
输出: true
示例2:
输入: preorder = "1,#"
输出: false
示例3:
输入: preorder = "9,#,#,1"
输出: false
思路:
如果一个结点没有子节点,那么它后面必然连接两个#,如果结点只有一个子节点,那么对于这棵子树来说,对应着3个#,即子节点一个,然后加上子节点的两个空节点#,这样看来对于一颗树的左子树,右子树,总会有#的个数比子树元素多一,两个子树加上根节点,那么总会有#的个数多一。
而我们知道前序序列是[根节点] [左子树序列] [右子树序列],那么我们遇到数字+1,遇到#号-1,最后如果等于-1,那么其实就满足条件。
class Solution:
def isValidSerialization(self, preorder: str) -> bool:
# 这里设置为1,避免最后判断-1,如果设置为0,那么最终结果和0比较即可
slots = 1
for i, ch in enumerate(preorder):
# 如果这里提前遇到了0,说明前面的数据#少了一个,不满足前序序列
if slots == 0: return False
# 如果是',',跳过
if ch == ',':
continue
# 如果是#,进行减一
if ch == '#':
slots -= 1
else:
# 这里需要去判断数字,由于数字可能不止一位,所以如果没遇到','说明还是同一个数字范畴
if i < len(preorder) - 1 and preorder[i+1] != ',':
continue
slots += 1
# 如果最终slot为0,说明满足条件
return slots == 0
1361、验证二叉树
二叉树上有 n 个节点,按从 0 到 n - 1 编号,其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]。
只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时,返回 true;否则返回 false。
如果节点 i 没有左子节点,那么 leftChild[i] 就等于 -1。右子节点也符合该规则。
注意:节点没有值,本问题中仅仅使用节点编号。
示例1:
输入:n = 4, leftChild = [1,-1,3,-1], rightChild = [2,-1,-1,-1]
输出:true
示例2:
输入:n = 4, leftChild = [1,-1,3,-1], rightChild = [2,3,-1,-1]
输出:false
示例3:
输入:n = 2, leftChild = [1,0], rightChild = [-1,-1]
输出:false
示例4:
输入:n = 6, leftChild = [1,-1,-1,4,-1,-1], rightChild = [2,-1,-1,5,-1,-1]
输出:false
思路:
这道题主要判断二叉树是否具有连通性,以及是否存在环。对于是否存在环,可以使用先序遍历的方式,看结点有没有出现过来判断。
是否具有连通性,如果出现多个根节点,那么对于已出现的节点来说,遍历一棵树,那么肯定有一些节点不出现,可以根据这个数量来进行判断。
class Solution:
def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool:
# 对结点数目进行统计,根节点的统计数目为0
nodes = [0]*n
for i in range(n):
if leftChild[i] != -1: nodes[leftChild[i]] += 1
if rightChild[i] != -1: nodes[rightChild[i]] += 1
# 找到根节点
root = -1
for node, count in enumerate(nodes):
if count == 0:
root = node
break
# 如果没有根节点,直接返回False
if root == -1: return False
# 从根节点开始进行先序遍历
queue = [root]
seen = {root,}
while queue:
cur = queue.pop(0)
# 遍历左右子树,如果已经出现,说明存在环,否则加入到队列和已出现队列中
leftVal = leftChild[cur]
if leftVal != -1:
if leftVal in seen: return False
queue.append(leftVal)
seen.add(leftVal)
rightVal = rightChild[cur]
if rightVal != -1:
if rightVal in seen: return False
queue.append(rightVal)
seen.add(rightVal)
# 判断节点联通性
return len(seen) == n