[LeetCode][Medium] VerifyPreorderSerialization of a BinaryTree 验证二叉树的前序序列化| Java

1,898 阅读1分钟

问题

Verify Preorder Serialization of a Binary Tree Medium

One way to serialize a binary tree is to use preorder traversal. When we encounter a non-null node, we record the node's value. If it is a null node, we record using a sentinel value such as '#'.

For example, the above binary tree can be serialized to the string "9,3,4,#,#,1,#,#,2,#,6,#,#", where '#' represents a null node.

Given a string of comma-separated values preorder, return true if it is a correct preorder traversal serialization of a binary tree.

It is guaranteed that each comma-separated value in the string must be either an integer or a character '#' representing null pointer.

You may assume that the input format is always valid.

  • For example, it could never contain two consecutive commas, such as "1,,3".

Note: You are not allowed to reconstruct the tree.

 

Example 1:

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

Example 2:

Input: preorder = "1,#"
Output: false

Example 3:

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

Constraints:

  • 1 <= preorder.length <= 10^4
  • preorder consist of integers in the range [0, 100] and '#' separated by commas ','.

解题思路

解题之前,我们先来复习一下什么是二叉树的前序序列化吧。按照下图中虚线所示的顺序,将图中二叉树序列化为F,B,A,D,C,E,G,I,H,就是前序序列化。如果按照本题的设定,用#表示空节点,那么前序序列化的结果就是F,B,A,#,#,D,C,#,#,E,#,#,G,#,I,H,#

image.png

那么要如何验证一个序列是否是合法的二叉树的前序序列呢?参照题中给出的样例可知,首先,父节点不能为#,比如9,#,#,1就是非法的;其次,父节点必须有两个子节点,比如1,#就是非法的。换句话说,判断是否合法的条件就是:

  1. 所有合法父节点都必须有两个子节点
  2. 所有子节点必须有合法的父节点

如何用程序来检查上述逻辑呢?我们首先要想办法定位一个节点的父节点位置和子节点位置,才能检查它们是否合法。将#自行脑补到上图中,我们可以发现,如果一个节点是左侧子节点,那么它的父节点就是它在序列中的前一个元素。反过来说,如果序列中一个元素是合法的父节点,即nums[i] != "#"时,那么它后面的一个元素就是它的左侧子节点。

相对应的,如果序列中一个元素的前一个元素不是合法的父节点,即nums[i - 1] == "#"时,那么这个元素就是一个右侧子节点。而右侧子节点的父节点需要到前面遍历过的合法父节点里面寻找。所以,我们需要将遍历过的合法父节点保存下来,用于右侧子节点的父节点查找

我们知道一个合法父节点只能有两个子节点,而它的左侧子节点已经确定是它后面的一个元素,所以在父节点查找中,它只能被使用一次。而且,在父节点查找中,我们并不关心节点的值,只要它不是#就可以。所以我们可以用一个计数器parentCandidateCnt来统计当前可用的合法父节点数。遍历序列的过程中,遇到合法的父节点则parentCandidateCnt++,遇到右侧子节点,则parentCandidateCnt--

如果最终parentCandidateCnt == 0,则表示所有合法父节点都找到了两个子节点。这样,判断是否合法的条件一就满足了。右侧子节点在执行parentCandidateCnt--时,如果parentCandidateCnt > 0,则表示父节点找到了,判断是否合法的条件二就满足了。

参考答案


public class Solution {
    public boolean isValidSerialization(String preorder) {
        String[] nums = preorder.split(",");
        int n = nums.length;

        int parentCandidateCnt = 0;

        for (int i = 0; i < n; i++) {
            // in preorder traversal, the left child will be right after it's parent
            // which means normally nums[i] is the left child of nums[i - 1]
            // but # can't be a parent, so when nums[i - 1] == #, nums[i] is should 
            // be a right child, and we need find its parent from candidates
            if (i > 0 && "#".equals(nums[i - 1])) {
                if (parentCandidateCnt > 0) {
                    parentCandidateCnt--;
                } else {
                    // if no candidate left, then return false
                    return false;
                }
            }
            // the nodes that is not # can be a parent node
            if (!"#".equals(nums[i])) {
                parentCandidateCnt++;
            }


        }
        // if all parent candidates have found their children return true
        return parentCandidateCnt == 0;
    }
}

image.png

拓展训练

来挑战一下类似的二叉树问题吧!

[Leetcode][Medium] Count Good Nodes in Binary Tree 统计二叉树中好节点的数目 | Java [LeetCode][Medium] Maximum Product of Splitted Binary Tree 分裂二叉树的最大乘积 | Java

或者到作者的LeetCode专栏中看看,有没有其他感兴趣的问题吧!

juejin.cn/column/6997…

资料链接

原题 leetcode.com/problems/ve…