[Prove safety -Offer] 37. Binary Serialization (traversal sequence, a preorder traversal, recursive, special cases)

1. Source title

Links: sequence of binary tree
Source: LeetCode-- "prove safety -Offer" special

2. Description title

Implement two functions are used to serialize and deserialize binary tree.

Example:

You can use the following binary tree:

     1    
    / \  
   2   3
      / \
     4   5

Serialized as "[1,2,3, null, null, 4,5]"

3. resolve title

Method a: Sequence Iterative Method traversal +

This is a Hardproblem, the idea is still very clear, the challenge in a string of data processing and final test on the 47, 48 receiving.

  • Sequence using the binary tree traversal sequence. Traverse the level is not uniquely identify a binary tree. If you encounter a node with an empty node '#'represents. Add a back of each node ','represents the end, you can uniquely identify a binary tree.
  • Above to give the binary tree of hierarchical sequence 1,2,3,#,#,4,5,#,#,#,#,
  • Then deserialized based on this sequence. (Note that the case of a negative judgment)

I talk about the pit encountered it:

  • First, in the sequence of the time, can not be directly used stringin the push_backmethod, it is hard on the test case 47, 48 may take +=the form of a string, it may be used character stream in the form of
  • Not merely use a sequence of hierarchically manner, i.e. not only added #to split the string, to do so one could not uniquely determine the binary tree, when the tree node value valgreater than 10, there is no way to directly remove the normal valvalue, since the #12#ambiguity, I do not know in the end is 1、2still12
  • The situation is negative nodes need to be addressed, this is indeed the beginning to ignore the
  • Rearmost #need to be removed, this is very easy to think

Basically a large pit in the above points are prompted to, it really Hardis not a simple general ... dfs、bfsI just put my whole temper ...

Bad Solution 1

Thinking too young to write so cool, I had not ... here is shaping valinto a chartype, so stringtake the case to bit can be taken directly.

See the code below:

// 没 AC,样例 47/48 过不去
// [1,null,2,null,3,null,4,null,5,null,6,null,...,999,null,1000] 单支树,IO极其密集

class Codec {
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string s;
        queue<TreeNode*> q;
        if (root) q.push(root);
        while (!q.empty()) {
            TreeNode *t = q.front(); q.pop();
            if (t) {
                s.push_back(t->val);	// 过不去,string 爆掉了
                q.push(t->left);
                q.push(t->right);
            } else {
                s.push_back('#');
            }
        }
        return s;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        int cnt = data.find_last_not_of('#');
        if (cnt != std::string::npos)
            data.erase(cnt + 1);
        else
            data.clear();   
        if (data.empty()) return nullptr;
        queue<TreeNode*> q;
        string val(data);
        TreeNode *res = new TreeNode(val[0]), *cur = res;
        q.push(cur);
        int i = 1;
        while (!q.empty()) {
            TreeNode *t = q.front(); q.pop();
            if (i > val.size() - 1) break;
            if (val[i] != '#') {
                cur = new TreeNode(val[i]);
                q.push(cur);
                t->left = cur;
                ++i;
            }
            else {
                ++i;
            }
            
            if (i > val.size() - 1) break;
            if (val[i] != '#') {
                cur = new TreeNode(val[i]);
                q.push(cur);
                t->right = cur;
                ++i;
            }
            else {
                ++i;
            }
        }
        return res;
    }
};

2 bad solution

Operating flow into the string can be properly read the test case 47, so read by character, integer will 123split into 1 2 3, three characters, in a subsequent string [ ]operation can not complete the output integer, it is being given. Even if the string processing, but only add the string #to the string dividing, no way to uniquely identify a binary tree, when the tree node value valgreater than 10, there is no way to directly remove the normal valvalue, since the #12#ambiguity, no know in the end is 1、2still 12, so to be considered uniquely identify a binary tree!

class Codec {
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
		queue<TreeNode*> q;
		q.push(root);
		stringstream ss;
		while (!q.empty()) {
			root = q.front();
			q.pop();
			if (root) {
				q.push(root->left);
				q.push(root->right);
				ss << root->val;
			}
			else {
				ss << '#';
			}
		}
		string data = ss.str();
		return data;
	}
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        int cnt = data.find_last_not_of('#');
        if (cnt != std::string::npos)
            data.erase(cnt + 1);
        else
            data.clear();   
        if (data.empty()) return nullptr;
        queue<TreeNode*> q;
        string val(data);
        TreeNode *res = new TreeNode(val[0] -'0'), *cur = res;
        q.push(cur);
        int i = 1;
        while (!q.empty()) {
            TreeNode *t = q.front(); q.pop();
            if (i > val.size() - 1) break;
            if (val[i] != '#' && i < val.size() - 1) {
                string tmp;
                while (i < val.size() && val[i] != '#' ) {
                    tmp += val[i];
                    ++i;
                }
                cur = new TreeNode(stoi(tmp));
                q.push(cur);
                t->left = cur;
            }
            else {
                ++i;
            }
            
            if (i > val.size() - 1) break;
            if (val[i] != '#') {
                string tmp;
                while (i < val.size() && val[i] != '#') {
                    tmp += val[i];
                    ++i;
                }
                cur = new TreeNode(stoi(tmp));
                q.push(cur);
                t->right = cur;
            }
            else {
                ++i;
            }
        }
        return res;
    }
};

Success edition

To get rid of these problems, and then solve the problem of negative numbers, to get this problem!

See the code below:

// 执行用时 :8 ms, 在所有 C++ 提交中击败了84.14%的用户
// 内存消耗 :10 MB, 在所有 C++ 提交中击败了100.00%的用户

/**
 * 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 {
private:
    string encode(TreeNode* root) {
        if (!root) return "#,";
        string res = "";
        queue<TreeNode*> q;
        q.push(root);
        while (!q.empty()) {
            TreeNode *t = q.front(); q.pop();
            if (t) {
                res += to_string(t->val) + ",";
                q.push(t->left);
                q.push(t->right);
            } else {
                res += "#,";
            }
        }
        return res;
    }

    TreeNode* takeNum(const string& data, int& p) {
        if (data[p] == '#') {
            p += 2;
            return NULL;
        }
        bool isN = false;
        if (data[p] == '-') {
            isN = true;
            p++;
        }
        int val = 0;
        while (data[p] != ',') {
            val = val * 10 + (data[p] - '0');
            p++;
        }
        p++;
        if (isN) {
            val = -val;
        }
        return new TreeNode(val);
    }

    TreeNode* decode(const string& data) {
        if (data[0] == '#') return NULL;
        int p = 0;

        TreeNode *root = takeNum(data, p);
        queue<TreeNode*> q;
        q.push(root);
        while (!q.empty()) {
            TreeNode *t = q.front(); q.pop();
            TreeNode *l = takeNum(data, p);
            TreeNode *r = takeNum(data, p);
            if (l) q.push(l);
            if (r) q.push(r);
            t->left = l;
            t->right = r;
        }
        return root;
    }

public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string s = encode(root);
        return s;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        TreeNode *root = decode(data);
        return root;
    }
};

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

Method two: preorder recursive solution +

String via the input and output streams istringstreamand ostringstream.

  • For serialization, starting from the root, if the node exists, then the current value stored in the output string, and each function can be serialized to its left and right child nodes recursively.
  • Go for serialization, first read the first character, in order to generate a root node, and then call to serialize function to the left and right child nodes of the root node recursively
  • Or deal with details of the problem, and almost above, will not repeat, but obviously a lot of simple recursive

See the code below:

// 执行用时 :40 ms, 在所有 C++ 提交中击败了63.53%的用户
// 内存消耗 :26.5 MB, 在所有 C++ 提交中击败了100.00%的用户

/**
 * 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:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        ostringstream out;
        serialize(root, out);
        return out.str();
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        istringstream in(data);
        return deserialize(in);
    }
private:
    void serialize(TreeNode *root, ostringstream &out) {
        if (root) {
            out << root->val << ' ';
            serialize(root->left, out);
            serialize(root->right, out);
        } else {
            out << "# ";
        }
    }
    TreeNode* deserialize(istringstream &in) {
        string val;
        in >> val;
        if (val == "#") return nullptr;
        TreeNode *root = new TreeNode(stoi(val));
        root->left = deserialize(in);
        root->right = deserialize(in);
        return root;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
Published 307 original articles · won praise 122 · views 60000 +

Guess you like

Origin blog.csdn.net/yl_puyu/article/details/104634270