[LeetCode] 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, 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 验证二叉树的先序序列化的更多相关文章
- 331 Verify Preorder Serialization of a Binary Tree 验证二叉树的前序序列化
序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录这个节点的值.如果它是一个空节点,我们可以使用一个标记值,例如 #. _9_ / \ 3 2 ...
- LeetCode Verify Preorder Serialization of a Binary Tree
原题链接在这里:https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/ 题目: One way to ...
- 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)
[LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...
- leetcode 331. Verify Preorder Serialization of a Binary Tree
传送门 331. Verify Preorder Serialization of a Binary Tree My Submissions QuestionEditorial Solution To ...
- LeetCode 331. 验证二叉树的前序序列化(Verify Preorder Serialization of a Binary Tree) 27
331. 验证二叉树的前序序列化 331. Verify Preorder Serialization of a Binary Tree 题目描述 每日一算法2019/5/30Day 27LeetCo ...
- 【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 ...
- 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, ...
- 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, ...
- 【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 ...
随机推荐
- 打造android偷懒神器———ListView的万能适配器
如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示ListView,当然,写N个自定义的适配器也是情理之中.虽说程序员本身就是搬砖,做这些枯燥无味的重复的事情也是理所当然,但 ...
- 没有神话,聊聊decimal的“障眼法”
0x00 前言 在上一篇文章<妥协与取舍,解构C#中的小数运算>的留言区域有很多朋友都不约而同的说道了C#中的decimal类型.事实上之前的那篇文章的立意主要在于聊聊使用二进制的计算机是 ...
- 账号密码管理系统Access版本
哈哈,花了我整整五天时间,账号密码管理系统软件终于成功编写完成了.由于我的各大论坛的账号密码特别多,记性又不好.所以一直以来都想要这么一个软件的,但是以前学习的都是面向过程的编程语言,一直无法实现这个 ...
- 在idea中maven项目jdk编译version总是跳到1.5
bug描述 项目ide: idea 项目构建工具:maven bug现象:每次修改pom之后,idea自动扫描一遍,然后发现默认的compile级别跳到5.0. 每次手动去setting里修改comp ...
- Unicode转义(\uXXXX)的编码和解码
在涉及Web前端开发时, 有时会遇到\uXXXX格式表示的字符, 其中XXXX是16进制数字的字符串表示形式, 在js中这个叫Unicode转义字符, 和\n \r同属于转义字符. 在其他语言中也有类 ...
- C#-#define条件编译
本文导读: C#的预处理器指令从来不会转化为可执行代码的命令,但是会影响编译过程的各个方面,常用的预处理器指令有#define.#undef.#if,#elif,#else和#endif等等,下面介绍 ...
- WebSocket异常 通常每个套接字地址(协议/网络地址/端口)只允许使用一次
websocket的实例:http://blog.csdn.net/for_cxc/article/details/51500185 问题: 新建一个连接通信没有问题,但是如果关闭再建立就会报错:通常 ...
- 03 通过Button打开另一个的frm
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { DialogResult re = MessageBox ...
- apache中怎么配置网站的默认首页
配置方法如下:1.首先需要打开Apache的配置文件httpd.conf文件,使用一般的编辑器或者记事本打开均可.2.找到或者搜索到如下字段:<IfModule dir_module> D ...
- Java中的多线程你只要看这一篇就够了
学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:279558494 我们一起学Java! 引 如果对什么是线程.什么是进程仍存有疑惑, ...