用JavaScript刷leetcode第331题-验证二叉树的前序序列化

188 阅读2分钟

一、前言

遍历字符串时,犯了一个错误,应该是以,为分隔符,来遍历。
式子1:

for(let i = 0; i < str.length; ++i) {
  if(str[i]) === ',') continue
  console.log(str[i])
}

式子2:

const strArr = str.split(',')
for(let i = 0; i < strArr.length; ++i) {
  console.log(strArr[i])
}

假设str = '3,4,5,6',那么上面的式子是等价的,但是如果str='30,40,50,60',那么很显然不相等。
这是我这次遇见的错误,记录下。

二、题目描述

image.png 原谅我比较懒,我直接从leetcode截图,欲知更加清楚的描述,请看leetcode题目链接

三、分析

  1. 事件与事件是完全包含关系, 用栈解决。 每个非空节点都有左右子节点。从根节点往下验证,需要验证每个节点,子节点验证成功,才能验证跟根节点,属于包含关系
  2. 每个非空几点都有两个子节点。故遇见一个非空节点,先抵掉了上层的一个子节点位置,然后自身又增加了两个子节点位置,故 栈顶-1, 压栈2
  3. 当自身的两个子节点都被占了位置,此时栈顶为0,需要执行出栈操作
  4. 遇见空节点,首先会抵掉上层的一个子节点的位置,但是由于空节点没有子节点,故不需要压栈

四、代码

git代码链接

/**
 * @param {string} preorder
 * @return {boolean}
 */
const isValidSerialization = function(preorder) {
  // 初始化栈, 初始化为1,可减少一些边界判断
  const stack = [1]
  // 将字符串转换成数组,直接遍历字符串可能会遇见‘92’这种多位数,也是为了减少一些边界,当然也可以直接遍历字符串,遇到数字,还要继续遍历直到找到‘,’号
  const preorderArr = preorder.split(',')

  // 遍历上面转换的数组
  for(let i = 0; i < preorderArr.length; ++i) {
    // 还没遍历完数组,栈为空时,代表这是错误的序列化
    if(!stack.length) return false

    // 遇见#号,栈顶元素-1,遇见非#号,栈顶元素-1,再入栈2。   注意这期间如果栈顶为0时,需要出栈
    if(preorderArr[i] === '#') {
      // 栈顶-1
      stack[stack.length - 1]--
      // 栈顶-1后判断栈顶是否为0,为0出栈
      (stack[stack.length - 1] === 0)  && stack.pop()
    } else {
      // 栈顶-1
      stack[stack.length - 1]--
      // 栈顶-1后判断栈顶是否为0,为0出栈
      (stack[stack.length - 1] === 0) && stack.pop()
      // 入栈2
      stack.push(2)
    }
  }

  // 遍历处理后,栈为空,代表时正确的二叉树前序序列
  return !stack.length
}