zoukankan      html  css  js  c++  java
  • 验证二叉树的前序序列化

    前言

    最近自己的学长面试的时候遇到这一道题了,然后把这道题出给了我。我的第一想法是根据前序遍历建立一个树结构,然后根据能否建立树来判断。但是题目要求不能重建树,所以自己确实不会做。在网上看了别人的解答才恍然大悟!这里总结一下大神们的解法。

    关于istringstream

    首先我们肯定要用istringstream来操作字符串,C++里面没有像Java那样有字符串的split函数(可以直接分割任意字符串);在C++里我们只能用getline这个函数从用户处获得字符,将字符串流的内容都存到一个vector数组中。我们可以先看一个简单的例子:

    int main()
    {
    	istringstream in("a,b,c,d,e,d,f");
    	string t = "";
    	while (getline(in, t, ','))
    	{
    		cout << t;
    		Sleep(100);
    	}
    	system("pause");
    	return 0;
    }
    

    istringstream类用于执行C++风格的串流的输入操作。
    ostringstream类用于执行C风格的串流的输出操作。
    strstream类同时可以支持C风格的串流的输入输出操作。
    这个函数是从string对象中读取字符到in中,然后在执行while (getline(in, t, ','))的时候表示遇到','就将已经读到的字符输出。上面的代码输出的结果为

    abcdedf
    

    解法一

    通过仔细观察我们可以发现两个规律:1.数字的个数总是比#号少一个;2.最后一个一定是#号。
    所以我们可以根据这两个规律,将最后一个字符“#”单独进行考虑,那么此时数字的个数和#的个数应该相同。所以可以初始化一个计数器专门记录数字的个数,当遇到数字则计数器+1,遇到#号-1;这样遍历到除了最后一个字符,则一定会有计数器=0!。所以最后遍历完的判断就是计数器是否等于0与最后一个字符是不是#。
    当然还有一些小细节要处理,比如“#,9,3,4,#”与“9,3,#,#,#,1”这两个错误案例,根节点首先不能为#,同时要确保在[0,i]这个范围内#的个数是不大于数字的个数的。所以可以通过在循环中判断是否会有计数器小于0的情况,代码如下:

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

    解法二

    解法二是边解析边判断,遇到不合题意的情况直接返回false,而不用全部解析完再来验证是否合法,提高了运算的效率。

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

    解法三

    这种解法就更加巧妙了,连字符串解析都不需要了,用一个变量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 = 1;
            preorder += ",";
            for (int i = 0; i < preorder.size(); ++i) {
                if (preorder[i] != ',') continue;
                if (--capacity < 0) return false;
                if (preorder[i - 1] != '#') capacity += 2;
            }
            return capacity == 0;
        }
    };
    
  • 相关阅读:
    说说如何用js实现一个模板引擎
    JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)
    React之ref详细用法
    安装SQL Server提示“重叠的IO操作正在进行”解决
    HDU3746 Cyclic Nacklace 【KMP】
    读&lt;大数据日知录:架构与算法&gt;有感
    VMware虚拟机安装Linux英文改中文系统并更新yum安装输入法
    数据结构的基本概念
    MFC TreeCtrl 控件(一):简单使用
    Java生成word文档
  • 原文地址:https://www.cnblogs.com/yunlambert/p/9188764.html
Copyright © 2011-2022 走看看