树—判断它是否是二叉树的前序遍历序列化

该博客探讨了如何确定给定的序列化字符串是否代表二叉树的前序遍历。内容涉及二叉树的性质以及如何通过算法验证序列化的正确性。

331. Verify Preorder Serialization of a Binary Tree

题目描述

利用前序遍历序列化二叉树时,遇到非空结点时,记录结点的值;如果是空节点,用#记录。 给定一个逗号分隔的字符串,判断它是否是二叉树的前序遍历序列化。不需重建二叉树

例子 Example 1:

Input: "9,3,4,#,#,1,#,#,2,#,6,#,#" Output: true

Example 2:

Input: "1,#" Output: false

Example 3:

Input: "9,#,#,1" Output: false

思想 (法1 - 出度入度之差) 入度等于出度~ 根节点:0个入度,2个出度;其他非空结点:1个入度,2个出度;空节点:1个入度,0个出度。 应保证出度-入度始终≥0,且最终差值为0。

遍历到每个结点时,因为入度为1,所以diff -= 1(考虑头结点,diff初始化为1)。如果非空,因为出度为2,所以diff += 2。

(法2 - 栈) 不断的砍掉叶子节点,最后看能不能全部砍掉。 遇到x # #的时候,就把它变为 # "9,3,4,#,#,1,#,#,2,#,6,#,#" 为例

模拟过程: 9,3,4,#,# => 9,3,# 继续读 9,3,#,1,#,# => 9,3,#,# => 9,# 继续读 9,#2,#,6,#,# => 9,#,2,#,# => 9,#,# => #

解法1 出度 - 入度
我们知道一个树(甚至图),所有节点的入度之和等于出度之和。那么可以根据这个条件进行有效性的判断。

对于二叉树,我们把空的地方也作为叶子节点(如题目中的#),那么有

所有的非空节点提供2个出度和1个入度(根除外)
所有的空节点但提供0个出度和1个入度
我们在遍历的时候,计算diff = outdegree – indegree. 当一个节点出现的时候,diff – 1,
因为它提供一个入度;当节点不是#的时候,diff+2(提供两个出度) 如果序列式合法的,那么遍历过程中diff >=0 且最后结果为0.

这里解释一下为什么diff的初始化为1.因为,我们加入一个非空节点时,都会先减去一个入度,再加上两个出度。
但是由于根节点没有父节点,所以其入度为0,出度为2.因此diff初始化为1,
是为了再加入根节点的时候,先减去一个入度,再加上两个出度,正好应该是2.class Solution(object):
    def isValidSerialization(self, preorder):
        """
        :type preorder: str
        :rtype: bool
        """
        diff = 1
        
        preorder = preorder.split(',')
        for x in preorder:
            diff -= 1
            if diff < 0:
                return False
            if x != '#':
                diff += 2
        return diff == 0
解法2 栈
我们的思路应该是这样的:判断一个二叉树是否合法的情况,那么应该是个递归或者循环问题。
那么解决问题的思路是从顶部向下分析还是从底下向顶部分析呢?
正确的结果应该是从二叉树的底部向上进行分析,因为我们可以通过#号判断是否是空节点,
然后判断最底下的叶子节点是否含有两个空孩子的方式,循环向上解决这个问题。

所以这个题的思路就很明了了:用一个栈,从字符串的左侧向右依次进栈,如果满足栈的后三位是数字,
#,#的模式时,说明可以构成合法的叶子节点,把这个叶子节点换成#号,代表空节点,然后继续遍历。
最后应该只剩下一个#,那么就是一个合法的二叉树。

class Solution(object):
    def isValidSerialization(self, preorder):
        """
        :type preorder: str
        :rtype: bool
        """    
        preorder = preorder.split(',')
        stack = []
        for x in preorder:
            stack.append(x)
            while len(stack) >= 3 and stack[-2:] == ['#','#'] and stack[-3] != '#':
                stack[-3:] = '#'
        return stack == ['#']
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值