leetcode树之验证二叉树

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

溪语流沙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值