# 331.verify Preorder Serialization of a Binary Tree

## 问题描述

[331. 验证二叉树的前序序列化][link] (Medium)

[link]: https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/

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

![](https://pic-upyun.zwyyy456.tech/smms/2023-12-26-065507.jpg)

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

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

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

你可以认为输入格式总是有效的

- 例如它永远不会包含两个连续的逗号，比如 `"1,,3"` 。

**注意：** 不允许重建树。

**示例 1:**

```
输入: preorder = "9,3,4,#,#,1,#,#,2,#,6,#,#"
输出: true
```

**示例 2:**

```
输入: preorder = "1,#"
输出: false
```

**示例 3:**

```
输入: preorder = "9,#,#,1"
输出: false
```

**提示:**

- `1 <= preorder.length <= 10⁴`
- `preorder` 由以逗号 `“，”` 分隔的 `[0,100]` 范围内的整数和 `“#”` 组成

## 解题思路

### 归约

本质上还是一种递归的思想，在前序遍历时，我们可以注意到，每个叶子结点必定跟随两个 null，因此，我们可以反过来，将连续的一个非空结点和两个空结点，归约为一个空结点，这个过程有点像消消乐，可以利用栈来实现这个过程，最后根据栈是否只剩下一个空结点来判断。

### 递归

递归的思路参照 [剑指 Offer 37. 序列化二叉树 (Hard)](https://leetcode.cn/problems/xu-lie-hua-er-cha-shu-lcof/)，不同之处在于我们只需要判断左子树和右子树是否满足要求而已，不需要返回它们的头结点。

## 代码

### 归约

```cpp
class Solution {
  public:
    void string2vec(string &preorder, vector<string> &strs) {
        for (int i = 0; i < preorder.size(); ++i) {
            int r = i;
            while (r < preorder.size() && preorder[r] != ',') {
                ++r;
            }
            strs.push_back(preorder.substr(i, r - i));
            i = r;
        }
    }
    bool isValidSerialization(string preorder) {
        vector<string> strs;
        string2vec(preorder, strs);
        int n = strs.size();
        stack<string> stk;
        for (int i = 0; i < n; ++i) {
            if (strs[i] != "#") {
                stk.push(strs[i]);
            } else {
                while (stk.size() >= 2 && stk.top() == "#") {
                    stk.pop();
                    if (stk.top() == "#") {
                        return false;
                    }
                    stk.pop();
                }
                stk.push("#");
            }
        }
        return stk.size() == 1 && stk.top() == "#";
    }
};
```

## 递归

```cpp
class Solution {
  public:
    void string2vec(string &preorder, vector<string> &strs) {
        for (int i = 0; i < preorder.size(); ++i) {
            int r = i;
            while (r < preorder.size() && preorder[r] != ',') {
                ++r;
            }
            strs.push_back(preorder.substr(i, r - i));
            i = r;
        }
    }
    bool dfs(vector<string> &strs, int &idx) {
        if (idx >= strs.size()) {
            return false;
        }
        if (strs[idx] == "#") {
            ++idx;
            return true;
        }
        ++idx;
        return dfs(strs, idx) && dfs(strs, idx);
    }
    bool isValidSerialization(string preorder) {
        vector<string> strs;
        string2vec(preorder, strs);
        int idx = 0;
        return dfs(strs, idx) && idx == strs.size();
    }
};
```

