首页 > 其他分享 >剑指 Offer 37. 序列化二叉树 - 力扣(LeetCode)

剑指 Offer 37. 序列化二叉树 - 力扣(LeetCode)

时间:2022-10-25 20:36:18浏览次数:80  
标签:TreeNode string Offer int 二叉树 push 序列化 节点

剑指 Offer 37. 序列化二叉树 - 力扣(LeetCode)

题目大意:

将一棵二叉树序列化成字符串,然后通过该字符串可以重新构造出二叉树

思路:

  • 看到将二叉树转化成字符串,首先想到的是可以通过将二叉树转换成先序遍历和中序遍历,然后通过先序遍历和中序遍历重新构造二叉树。然而这个方法失败了,因为存在节点值相同的节点,这样就无法在中序序列里面找到先序遍历对应的值。

  • 因此我们可以考虑使用BFS,但是使用BFS的话,要如何反序列化呢?

  • 我们知道,当一颗二叉树是满二叉树时,如果节点索引是从0开始编号的话,对于索引位i的节点,他的左孩子的索引是2*i+1,右孩子的索引是2*i+2.因此我们可以考虑通过填充null将二叉树改造成满二叉树。然而这种想法是无法实现的,当二叉树退化成一条链的时候,想要将其扩充成满二叉树,时间和空间复杂度都会爆炸。

  • 其实上面的结论可以推广到不是满二叉树的情况。首先,左孩子和右孩子的索引肯定是相差一。然后我们可以这样思考:对于索引为i的节点,我们设该节点之前存在m个null节点。因此在i之前存在(i-m+1)个非null节点,除根节点外,每增加一个非null节点,该节点首先会取代一个null节点,然后会增加两个null子节点。因此每增加一个非null节点需要用掉2个索引。而root节点会用掉3个索引。综上,节点i之前的节点会用掉3+(i-m+1-2)*2=2*(i-m)+1,因此i的左孩子的索引为(i-m)*2+1,右孩子为(i-m)*2+2.

因此我们可以递归构建二叉树:

点击查看代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:
    vector<int> v;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        queue<TreeNode*> q;
        int cnt=0;
        q.push(root);
        string s="";
        while (!q.empty())
        {
            TreeNode* temp=q.front();
            q.pop();
            if (temp){
                s.append(" "+to_string(temp->val));
                q.push(temp->left);
                q.push(temp->right);
                v.push_back(cnt);
            }else{
                s.append(" -223221");
                cnt++;
                v.push_back(cnt);
            }
        }
        return s;
    }
    TreeNode* dfs(int k,vector<int>& data){
        //cout<<k<<" ";
        if (data[k]==-223221)
        {
            return NULL;
        }else{
            TreeNode* root=new TreeNode(data[k]);
            root->left=dfs(2*(k-v[k])+1,data);
            root->right=dfs(2*(k-v[k])+2,data);
            return root;
        }
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        //cout<<data.length();
        vector<int> arr;
        int pre=0;
        int i=1;
        data.push_back(' ');
        while (i<data.length())
        {
            if (data[i]==' '){
                arr.push_back(stoi(string(data,pre+1,i-pre-1)));
                pre=i;
            }
            i++;
        }
        TreeNode* root=dfs(0,arr);
        return root;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

事实上,如果使用BFS反序列化,就不需要知道孩子节点的索引,因为只有非null节点才有孩子,因此可以使用一个指针指向第二个节点(因为第一个节点要作为root),然后每次遇到非空节点,都将指针指向的节点挂到该非空节点之下,然后指针右移。

点击查看代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:
    //vector<int> v;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        queue<TreeNode*> q;
        //int cnt=0;
        q.push(root);
        string s="";
        while (!q.empty())
        {
            TreeNode* temp=q.front();
            q.pop();
            if (temp){
                s.append(" "+to_string(temp->val));
                q.push(temp->left);
                q.push(temp->right);
                //v.push_back(cnt);
            }else{
                s.append(" #");
                //cnt++;
                //v.push_back(cnt);
            }
        }
        return s;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        //cout<<data.length();
        vector<TreeNode*> arr;
        int pre=0;
        int i=1;
        data.push_back(' ');
        while (i<data.length())
        {
            if (data[i]==' '){
                string tt=string(data,pre+1,i-pre-1);
                if (tt[0]=='#') 
                    arr.push_back(NULL);
                else
                    arr.push_back(new TreeNode(stoi(tt)));
                pre=i;
            }
            i++;
        }
        if (arr.size()==0 or arr[0]==NULL)
        {
            return NULL;
        }
        int pos=1;
        for (int i=0;i<arr.size();i++)
        {
            if (arr[i]==NULL)
                continue;
            arr[i]->left=arr[pos++];
            arr[i]->right=arr[pos++];
        }
        return arr[0];
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

标签:TreeNode,string,Offer,int,二叉树,push,序列化,节点
From: https://www.cnblogs.com/sjw-blogs/p/16826195.html

相关文章

  • 算法】字符串复原IP地址,从前序与中序编辑序列构造二叉树
    算法学习有些时候是枯燥的,一点一点学习算法第一题算法题目描述对给定的两个日期之间的日期进行遍历,比如startTime是2014-07-11;endTime是2014-08-11如何把他们之间......
  • 已知后序和中序输出前序(二叉树)
    已知后序和中序输出前序(二叉树)给出二叉树的后序遍历和中序遍历,要求输出二叉树的前序遍历:后序:2315764中序:1234567分析:由后序遍历的特性可知,后序的最后一个......
  • HDU 1203 I NEED A OFFER!
    题目链接:​​传送门​​题面:INEEDAOFFER!ProblemDescriptionSpeakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了......
  • python实现二叉树并且遍历
    python实现二叉树并且遍历2.1二叉树的遍历2.1.1前序遍历(根左右)二叉树的前序遍历的步骤如下:访问树的根节点---->访问当前节点的左子树---->若当前节点无左子树,访......
  • 关于存储二叉树
    !前置芝士:二叉树的性质\(1.\)二叉树中,第\(i\)层最多有\(2i-1\)个结点。\(2.\)如果二叉树的深度为\(K\),那么此二叉树最多有\(2K-1\)个结点。二叉树中,终端结点数(叶子结......
  • xml 反序列化处理
    usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Net;usingSystem.IO;usingSystem.Collections.Specialized;......
  • BZOJ 2111([ZJOI2010]Perm 排列计数-乘法逆元+完全二叉树模型+数列分数表示法)
    2111:[ZJOI2010]Perm排列计数TimeLimit: 10Sec  MemoryLimit: 259MBSubmit: 478  Solved: 283[​​Submit​​][​​Status​​][​​Discuss​​]......
  • 剑指 Offer 56 - II. 数组中数字出现的次数 II - 力扣(LeetCode)
    剑指Offer56-II.数组中数字出现的次数II-力扣(LeetCode)在一个数组nums中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。思路......
  • 7-1 二叉树遍历应用
    读入用户输入的一串字符串,将字符串按照先序遍历建立一个二叉树。其中“#”表示的是空格,代表空树。再对建立好的二叉树进行中序遍历,输出遍历结果。#include<iostream>#i......
  • 二叉树的四种遍历顺序
    题目102二叉树的层序遍历思路用队列实现层序遍历。代码#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,righ......