LeetCode/solutions/331. Verify Preorder Serialization of a Binary Tree.md

3.5 KiB
Raw Permalink Blame History

331. Verify Preorder Serialization of a Binary Tree

思路

题目给定一个字符串,判断这个字符串能否表示成一个二叉树。

字符串中每个节点用逗号分割,所以我们可以先用istringsteam将这个字符串转换成输入流,然后用getline并设置分隔符delim为逗号默认是换行符不断获得每个节点node。

istringstream in(preorder);
string node;
while(getline(in, node, ',')){
   .....
}

思路一

这题的分类是栈,我们可以用栈解决,参考讨论区

开辟一个栈然后不断检查获得的节点node有两种情况:

  1. node为一个数说明接下来会开辟一个以这个节点为根的子树所以我们将其压栈
  2. node为#,此时根据栈顶划分又有两种情况:
  2.1 栈顶为一个数,说明当前的#为左空节点,压栈就可以了(等待它的兄弟)。
  2.2 栈顶为#,说明当前#为右空节点,栈顶为其左兄弟,应该出栈两次将其左兄弟及父亲删除,
      然后回到第2.1开始不断循环,直到栈顶为一个数或者栈空,最后才将当前#入栈。

2.2中出栈两次是连贯的过程所以如果第一次出栈后栈就空了则可以直接返回false。检查完毕后如果栈中只剩下一个元素且就为#即可返回true否则返回false。

以"9,3,4,#,#,1,#,#,2,#,6,#,#"为例的话上述过程如下图所示:

时空复杂度均为O(n)。

思路二

讨论区发现有一个不用栈的方法,常数时间复杂度。

在二叉树中,如果把空节点#当做是叶子,那么

  • 所有非空节点有2个出度1个入度除了根节点
  • 所有空节点(即#有0个出度1个入度。

我们维持一个变量diff代表 出度减去入度初始为1因为根节点入度为0而不是1。遇到当前节点node时先将diff减去1因为不管node是否为空都有1个入度 如果非空(即不是#那还应该将diff加上2。这个过程中如果一旦遇到diff小于0则可返回false最后返回 diff==0

时间复杂度O(n), 空间复杂度O(1)。

C++

思路一

class Solution {
public:
    bool isValidSerialization(string preorder) {  
        istringstream in(preorder);
        string node;
        
        stack<char>stk;
        while(getline(in, node, ',')){
            if(node != "#") stk.push('n');
            else{
                while(!stk.empty() && stk.top() == '#'){
                    stk.pop();
                    if (stk.empty()) return false;
                    stk.pop();
                }
                stk.push('#');
            }
        }
        return stk.size() == 1 && stk.top() == '#';
    }
};

思路二

class Solution {
public:
    bool isValidSerialization(string preorder) {  
        istringstream in(preorder);
        string node;
        
        int diff = 1;
        while(getline(in, node, ',')){
            if (--diff < 0) return false;
            if (node != "#") diff += 2;
        }
        return diff == 0;
    }
};