【路飞】算法-验证二叉树的前序序列化

322 阅读2分钟

二叉树的前序遍历 先访问根节点,然后以同样的方式访问左子树和右子树的方式称为前序遍历 题目链接 LeetCode :leetcode-cn.com/problems/ve… 题目简介 序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #

image.png
例如,上面的二叉树可以被序列化为字符串 "9,3,4,#,#,1,#,#,2,#,6,#,#",其中 # 代表一个空节点。

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

每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 '#' 。

示例

输入: "9,3,4,#,#,1,#,#,2,#,6,#,#"
输出: true
输入: "1,#"
输出: false

解题思路 使用数据结构--栈。
定义一个概念,叫做曹位,一个曹位可以被看作是当前二叉树中正在等待被节点填充的那些位置。
二叉树的建立也伴随着曹位数量的变化,每当遇到一个节点时:

  • 如果遇到了空节点,则需要消耗一个曹位(当前子节点为null)
  • 如果遇到了非空节点,则除了消耗一个曹位外,还要再补充两个曹位(两个子节点)
  • 根节点的曹位特殊处理和定义
    栈中的的每个元素,代表了对应节点剩余曹位的数量,而栈顶元素就对应着下一步可用的曹位数量
    若栈顶元素变为0,就立即弹出(两个子节点已满,无可用曹位)
    遍历结束后,若栈为空,说明没有待填充的曹位,因此是一个合法的序列。
    否则若栈不为空,则序列不合法。
    若在遍历过程中,曹位数量不足,则序列不合法

代码实现

/**
 * @param {string} preorder
 * @return {boolean}
 */
 var isValidSerialization = function(preorder){
     const n = preorder.length; // 定义字符串的长度
     const stack = [1];  // 定义栈,默认有一个二叉树的根节点
     let i = 0; // 记录字符串移动的变化
     while(i < n){
         // 循环没结束,但是没有可以使用的曹位,则证明不合法
         if(!stack.length) return false;
         // 若遇到【,】,则直接向后走一位
         if(preorder[i] === ','){
             ++i;
         }
         // 空节点消耗一个曹位
         else if(preorder[i] === '#'){
             // 栈顶元素-1
             stack[stack.length-1]--;
             // 若栈顶元素为0 ,这无曹位可用,弹出栈顶元素
             if(stack[stack.length-1] === 0){
                 stack.pop();
             }
             // 指针向后移动一位
             ++i;
         }
         else {
             while(i < n && preorder[i] !== ','){
                 // 正常字符时指针向后移动一位
                 ++i;
             }
             // 消耗一个曹位
             stack[stack.length-1]--;
             if(stack[stack.length-1] === 0){
                 // 若栈顶元素为0 ,这无曹位可用,弹出栈顶元素
                 satck.pop();
             }
             // 补充两个曹位
             stack.push(2);
         }
     }
     return stack.length === 0;
 }