实际上这题比较难的就是要考虑清楚,序列化后的整棵树应该是什么形状。
我们应该让整个二叉树的 左节点或右节点为空的节点的空节点 也加入到序列化后的列表中;
这是为什么呢?你可以尝试着按这个思路试试,只要 左节点或右节点为空的节点的空节点 也加入序列化列表
我们在反序列化时就可以简单的判断当前节点的情况,来决定是否将其插入到树中。

序列化:

通过上面简单分析,我可以试试实现序列化,既然我们要添加左右空节点,那么它肯定是需要
和别的节点有所不同,我们用一个空节点的标识 ~ 来标识,当然也可以用其他的标识,只要不与
题目中的节点可能的值冲突,并且我们用这个标识来创一个空节点(得益于js的弱类型),用于占位。

function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
}

const sign = '~';					// 空节点的标识
const node = new TreeNode(sign);	// 创建一空占位的空节点

const delimiter = ',';				// 这个分隔符只要与标识和数值不冲突即可

function Serialize(pRoot)
{
    if(!pRoot)    return ''
    const queue = [pRoot];
    const tree = [];
    while(queue.length) {
        const top = queue.shift();
      	// 占位空节点和真实的节点都需要加入到序列化列表中,用于反序列化
        tree.push(top.val)	
      	if(top === node) continue;        // 占位的空节点我们并不对其扩展
      
        if(top.left) {					  // 如果有左节点就扩展
            queue.push(top.left);
        } else {
            queue.push(node);			 // 如果没有左节点说明它是末梢节点
        }
        if(top.right) {				 	 // 类似
            queue.push(top.right);
        } else {
            queue.push(node);
        }
    }
    // 之所以这里又加了个 ',' 用于方便反序列化,这样反序列化就无须知道字符串格式
  	// 只要拿到时用分隔符进行分割即可
    return `${tree.join(delimiter)}${delimiter}`;		
}

function Deserialize(s)
{
    // write code here
    if(!s)    return null;
  	// 直接使用分割符进行分隔,按自己的规则生成树即可
    s = s.split(delimiter);
    const tree = new TreeNode(s[0]);
    const queue = [tree];
    for(let i = 1; i < s.length - 1; i += 2) {
        const top = queue.shift();
        const leftV = s[i];
        const rightV = s[i + 1];
        // 判断这是不是一个占位的值,如果不是就可以生成节点
        if(leftV !== sign) {
            top.left = new TreeNode(leftV);
          	// 生成完节点也需要将该节点加入到队列中,用于下次扩展
            queue.push(top.left);
        }
        if(rightV !== sign) {
            top.right = new TreeNode(rightV);
            queue.push(top.right);
        }
    }
    return tree;
}
module.exports = {
    Serialize : Serialize,
    Deserialize : Deserialize
};