剑指37题解 | #序列化二叉树#

序列化二叉树

https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
/*
	遵循思想,通俗易解
    层序遍历,空格用#字符
    层序遍历时,有#表示空格时,不需要添加换行标记,因为遵循层序遍历时,一个节点会读两个子节点规律的,对于空的,使用#表示
    编码时,使用了Vector容器标记每层的子节点存在情况,对于都为空时,那么不再填充#
    编解码时,均采用数字记录器来表示空节点,目的方便判断
*/
#include <algorithm>
#include <cstring>
#include <limits>
#include <queue>
#include <sstream>
#include <string>
#include <vector>
class Solution {
public:
    // char* c;
    char* Serialize(TreeNode *root) {
        if(!root) return nullptr;    
        string s;
        queue<TreeNode*> q;
        q.push(root);
        vector<int> v;      // 记录器,记录每一层的节点非空情况
        v.push_back(1);     // 记录root节点层存在非空节点
        TreeNode* tmp_node = new TreeNode(151);     // 自定义一个假节点,方便处理空节点(补充说明,一开始采用整体返回数值字符串,奈何一直超过内存限制,解码会失败,所以假节点还是在字符串中表示为#)
        while (!q.empty()) {
            bool flag = count(v.begin(), v.end(), 1);   // 目的确保下一层中存在非空子节点
            v.clear();  // 下一层时,需要重置记录器
            int num = q.size(); // 记录当前层含假节点(空节点)在内的节点数目
            // 开始层序遍历
            for(int i = 0; i < num; ++i)
            {
                TreeNode* tmp = q.front();
                q.pop();
                if(flag){
                    if(tmp->val != 151){    // 非假(空)节点时,直接入string容器
                        s.append(to_string(tmp->val) + ',');
                    }
                    else{
                        s.append("#,");     // 空
                    }
                }
                if(tmp->left){  // 左子节点存在时
                    q.push(tmp->left);  // 入队
                    v.push_back(1);     // 记录当前层中的子节点存在
                }
                else if(tmp->val != 151){
                    q.push(tmp_node);   // 对于空节点,这里给个假节点作为标记,不然后面没法加入 #
                    v.push_back(0);     // 记录子节点为空
                }
                if(tmp->right)          // 意义同上
                {
                    q.push(tmp->right);
                    v.push_back(1);
                }
                else if(tmp->val != 151){
                    q.push(tmp_node);
                    v.push_back(0);
                }
            }
        }
        // char* c = (char*) s.data();          // 这种写法会导致解码时拿到是一个空字符串
        char* res = new char(s.length()+1);     // 需要给返回指针开辟一个空间,否则反解析无法接收字符串
        strcpy(res, s.c_str());                 // 注意字符串后面会有一个 ‘\0’ 结尾,所以开辟空间时,得+1
        // std::cout << " 编码: " << s << std::endl;
        return res;
    }

    int getVal(string s, int& k)    // 获取数值,对于#字符,返回-1
    {
        int val = 0;
        if(s[k] == '#') k+=1;
        for(; k < s.size()&& s[k] != ','; ++k)
        {
            val = val * 10 + (s[k] - '0');  // int类型跟字符转换就是差个 '0' 
        }
        return val==0?-1:val;
    }
    TreeNode* Deserialize(char *str) {
        if(!str) return nullptr;
        string s = str;
        // std::cout << s << std::endl; // 注意字符串包含了 数字字符、#、 , 三者
        int val = 0;
        int k = 0;
        val = getVal(s, k);
        k += 1;
        TreeNode* root = new TreeNode(val);
        queue<TreeNode*> q;
        q.push(root);
        // 层序遍历解码重建树
        while (!q.empty() && k < s.size()) {
            int num = q.size();
            for(int j = 0; j < num ;++j)
            {
                TreeNode* cur = q.front();
                q.pop();
                val = getVal(s, k);
                if (val != -1) {
                    cur->left = new TreeNode(val);
                    q.push(cur->left);
                }
                val = getVal(s, ++k);
                if(val != -1){
                    cur->right = new TreeNode(val);
                    q.push(cur->right);
                }
                ++k;
            }
        }
        return root;
    }
};

挤挤刷刷! 文章被收录于专栏

记录coding过程

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务