One way to serialize a binary tree is to use pre-order 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 #.

     _9_
/ \
3 2
/ \ / \
4 1 # 6
/ \ / \ / \
# # # # # #

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, verify whether it is a correct preorder traversal serialization of a binary tree. Find an algorithm without reconstructing the tree.

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".

Example 1:

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

Example 2:

Input: "1,#"
Output: false

Example 3:

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

Credits:
Special thanks to @dietpepsi for adding this problem and creating all test cases.

这道题给了我们一个类似序列化二叉树后的字符串,关于二叉树的序列化和去序列化可以参见我之前的博客Serialize and Deserialize Binary Tree,这道题让我们判断给定是字符串是不是一个正确的序列化的二叉树的字符串。那么根据之前那边博客的解法,我们还是要用istringsteam来操作字符串,C++里面没有像Java那样有字符串的split函数,可以直接分隔任意字符串,我们只能使用getline这个函数,来将字符串流的内容都存到一个vector数组中。我们通过举一些正确的例子,比如"9,3,4,#,#,1,#,#,2,#,6,#,#" 或者"9,3,4,#,#,1,#,#,2,#,6,#,#"等等,可以观察出如下两个规律:

1. 数字的个数总是比#号少一个

2. 最后一个一定是#号

那么我们加入先不考虑最后一个#号,那么此时数字和#号的个数应该相同,如果我们初始化一个为0的计数器,遇到数字,计数器加1,遇到#号,计数器减1,那么到最后计数器应该还是0。下面我们再来看两个返回False的例子,"#,7,6,9,#,#,#"和"7,2,#,2,#,#,#,6,#",那么通过这两个反例我们可以看出,如果根节点为空的话,后面不能再有节点,而且不能有三个连续的#号出现。所以我们再加减计数器的时候,如果遇到#号,且此时计数器已经为0了,再减就成负数了,就直接返回False了,因为正确的序列里,任何一个位置i,在[0, i]范围内的#号数都不大于数字的个数的。当循环完成后,我们检测计数器是否为0的同时还要看看最后一个字符是不是#号。参见代码如下:

解法一:

class Solution {
public:
bool isValidSerialization(string preorder) {
istringstream in(preorder);
vector<string> v;
string t = "";
int cnt = ;
while (getline(in, t, ',')) v.push_back(t);
for (int i = ; i < v.size() - ; ++i) {
if (v[i] == "#") {
if (cnt == ) return false;
--cnt;
} else ++cnt;
}
return cnt == && v.back() == "#";
}
};

下面这种解法由网友edyyy提供,不需要建立解法一中的额外数组,而是边解析边判断,遇到不合题意的情况直接返回false,而不用全部解析完再来验证是否合法,提高了运算的效率。我们用一个变量degree表示能容忍的"#"的个数,degree初始化为1。再用一个布尔型变量degree_is_zero来记录degree此时是否为0的状态,这样的设计很巧妙,可以cover到"#"开头,但后面还跟有数字的情况,比如"#,1,2"这种情况,当检测到"#"时,degree自减1,此时若degree为0了,degree_is_zero赋值为true,那么如果后面还跟有其他东西的话,在下次循环开始开始前,先判断degree_is_zero,如果为true的话,直接返回false。而当首字符为数字的话,degree自增1,那么此时degree就成了2,表示后面可以再容忍两个"#"。当循环退出的时候,此时判断degree是否为0,因为我们要补齐"#"的个数,少了也是不对的,参见代码如下:

解法二:

class Solution {
public:
bool isValidSerialization(string preorder) {
istringstream in(preorder);
string t = "";
int degree = ;
bool degree_is_zero = false;;
while (getline(in, t, ',')) {
if (degree_is_zero) return false;
if (t == "#") {
if (--degree == ) degree_is_zero = true;
} else ++degree;
}
return degree == ;
}
};

下面这种解法就更加巧妙了,连字符串解析都不需要了,用一个变量capacity来记录能容忍"#"的个数,跟上面解法中的degree一个作用,然后我们给preorder末尾加一个逗号,这样可以处理末尾的"#"。我们遍历preorder字符串,如果遇到了非逗号的字符,直接跳过,否则的话capacity自减1,如果此时capacity小于0了,直接返回true。此时再判断逗号前面的字符是否为"#",如果不是的话,capacity自增2。这种设计非常巧妙,如果逗号前面是"#",我们capacity自减1没问题,因为容忍了一个"#";如果前面是数字,那么先自减的1,可以看作是初始化的1被减了,然后再自增2,因为每多一个数字,可以多容忍两个"#",最后还是要判断capacity是否为0,跟上面的解法一样,我们要补齐"#"的个数,少了也是不对的,参见代码如下:

解法三:

class Solution {
public:
bool isValidSerialization(string preorder) {
int capacity = ;
preorder += ",";
for (int i = ; i < preorder.size(); ++i) {
if (preorder[i] != ',') continue;
if (--capacity < ) return false;
if (preorder[i - ] != '#') capacity += ;
}
return capacity == ;
}
};

类似题目:

Serialize and Deserialize Binary Tree

参考资料:

https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/

https://discuss.leetcode.com/topic/36035/2-lines-java-using-regex

https://discuss.leetcode.com/topic/45326/c-4ms-solution-o-1-space-o-n-time

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Verify Preorder Serialization of a Binary Tree 验证二叉树的先序序列化的更多相关文章

  1. 331 Verify Preorder Serialization of a Binary Tree 验证二叉树的前序序列化

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

  2. LeetCode Verify Preorder Serialization of a Binary Tree

    原题链接在这里:https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/ 题目: One way to ...

  3. 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)

    [LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  4. leetcode 331. Verify Preorder Serialization of a Binary Tree

    传送门 331. Verify Preorder Serialization of a Binary Tree My Submissions QuestionEditorial Solution To ...

  5. LeetCode 331. 验证二叉树的前序序列化(Verify Preorder Serialization of a Binary Tree) 27

    331. 验证二叉树的前序序列化 331. Verify Preorder Serialization of a Binary Tree 题目描述 每日一算法2019/5/30Day 27LeetCo ...

  6. 【LeetCode】Verify Preorder Serialization of a Binary Tree(331)

    1. Description One way to serialize a binary tree is to use pre-order traversal. When we encounter a ...

  7. LeetCode OJ 331. Verify Preorder Serialization of a Binary Tree

    One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, ...

  8. Verify Preorder Serialization of a Binary Tree -- LeetCode

    One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, ...

  9. 【leetcode】331. Verify Preorder Serialization of a Binary Tree

    题目如下: One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null ...

随机推荐

  1. 学习SpringMVC——拦截器

    拦截器,顾名思义就是用来拦截的. 那什么是拦截,又为什么要拦截.对于Spring MVC来说,拦截器主要的工作对象就是用户的请求,拦截下来之后,我们可以在拦截的各个阶段悉心呵护[为所欲为].常见的比如 ...

  2. python获取命令行输出结果

    #coding=utf-8 import os   command = 'ping www.baidu.com ' #可以直接在命令行中执行的命令 r = os.popen(command) #执行该 ...

  3. Node学习笔记(二):事件驱动

    接触Node,提得最多的可能就是回调,异步非阻塞处理,思前想后,JavaScript从前端语言过渡到服务器端,最大的劣势可能就是线程,当然这方面的不足现在也被慢慢弥补起来了(很多第三方的npm包可供下 ...

  4. 【无私分享:ASP.NET CORE 项目实战(第五章)】Repository仓储 UnitofWork

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 本章我们来创建仓储类Repository 并且引入 UnitOfWork 我对UnitOfWork的一些理解  UnitOfW ...

  5. python 数据类型---布尔型& 字符串

    python数据类型-----布尔型 真或假=>1或0 >>> 1==True True >>> 0==False True python 数据类型----- ...

  6. wampserver服务器无法启动(图标颜色不对)

    1.服务器一直无法启动,图标颜色一直显示黄色,并且不可用. 2.解决办法: (1) C:\wamp\bin\apache\apache2.4.9\bin ->httpd.exe  找到该文件 ( ...

  7. 遭遇Web print

    一直都知道Web打印还不太成熟,以前IE横行时,普遍都是采用打印相关的ActiveX控件,有些国产厂家做得不错,只是那时还没有付费能力,没有太多关注.而纯粹基于Web标准的打印,浏览器对CSS pri ...

  8. Delphi_07_Delphi_Object_Pascal_基本语法_05_函数参数

    这里主要讨论Delphi中函数.方法的相关内容. 一.工程文件 { Delphi语法方法和函数 1.方法 2.函数 } program Routine; {$APPTYPE CONSOLE} uses ...

  9. 同步辅助类CountDownLatch用法

    CountDownLatch是一个同步辅助类,犹如倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则使当前线程处于等待状态,调用countDow ...

  10. 判断终端的js

    $(function(){ var sUserAgent = navigator.userAgent.toLowerCase(); var bIsIpad = sUserAgent.match(/ip ...