【二叉树】验证二叉树的前序序列化

0x00 题目

序列化二叉树的一种方法是使用 前序遍历
当遇到一个 非空 节点时,可以记录下这个节点的值
如果它是一个 节点,可以使用一个标记值记录,例如 #

给定一串以 逗号 分隔的序列
验证它是否是 正确 的二叉树的 前序 序列化
编写一个在 重构树的条件下的可行算法

每个以逗号分隔的字符,是一个整数
或者是一个表示 null 指针的 #
你可以认为输入格式总是有效的
例如它永远不会包含两个连续的逗号,比如 1,,3


0x01 思路

方法一:

先定义一个概念,叫做 槽位

一个 槽位 可以被看作当前二叉树中正在等待 被节点填充 的那些位置

二叉树的建立也伴随着 槽位 数量的变化。每当遇到一个节点时:
a.如果遇到了 节点,则要 消耗 一个槽位
b.如果遇到了 非空 节点,则除了 消耗 一个槽位外,还要再 补充 两个槽位

使用栈来维护槽位的变化
栈中的每个 元素,代表了对应节点处剩余槽位的 数量
而栈顶元素就对应着下一步可用的槽位数量

当遇到 节点时,仅将栈顶元素减 1
当遇到 非空 节点时,将栈顶元素减 1 后,再向栈中压入一个 2

无论何时,如果栈顶元素变为 0,就立刻将栈顶 弹出
遍历结束后,若栈 为空
说明没有待填充的槽位,因此是一个 合法 序列

否则若栈 不为空,则序列不合法
此外,在遍历的过程中,若槽位数量 不足,则序列不合法


方法二:计数

能否将方法一的空间复杂度优化至 O(1) 呢?
回顾方法一的逻辑,如果把栈中元素看成一个 整体
即所有剩余槽位的 数量,也能维护槽位的 变化

因此,只维护一个 计数器,代表栈中所有元素之
其余的操作逻辑均可以保持不变


0x02 解法

语言:Swift

解法一:

func isValidSerialization(_ preorder: String) -> Bool {
    let n = preorder.count
    var i = 0
    var stack: [Int] = [1]
    
    while i < n {
    	// 槽位数量不足
        if stack.isEmpty {
            return false
        }
        
        // 取一个字符
        let sIndex = preorder.startIndex
        var index = preorder.index(sIndex, offsetBy: i)
        let c = preorder[index]
        
        // 判断字符
        if c == "," {
            i += 1
        }else if c == "#" {
        	// 空节点
            let last = stack.last! - 1
            if last == 0 {
                stack.removeLast()
            }else{
                stack[stack.count-1] = last
            }
            i += 1
        }else{
            // 读一个数字
            var s = Character("c")
            while i < n && s != "," {
                index = preorder.index(sIndex, offsetBy: i)
                s = preorder[index]
                i += 1
            }
            
            let last = stack.last! - 1
            if last == 0 {
                stack.removeLast()
            }else{
                stack[stack.count-1] = last
            }
            stack.append(2)
        }
    }
    return stack.isEmpty
}

解法二:

func isValidSerializationV2(_ preorder: String) -> Bool {
    let n = preorder.count
    var i = 0
    var slots = 1
    
    while i < n {
        if slots == 0 {
            return false
        }
        
        let sIndex = preorder.startIndex
        var index = preorder.index(sIndex, offsetBy: i)
        let c = preorder[index]
        
        if c == "," {
            i += 1
        }else if c == "#" {
            slots -= 1
            i += 1
        }else{
            // 读一个数字
            var s = Character("c")
            while i < n && s != "," {
                index = preorder.index(sIndex, offsetBy: i)
                s = preorder[index]
                i += 1
            }
            slots += 1 // slots = slots - 1 + 2
        }
    }
    return slots == 0
}


小笔记应用

请添加图片描述


猜你喜欢

转载自blog.csdn.net/xjh093/article/details/123130354
今日推荐