【我也想刷穿 LeetCode啊】449. 序列化和反序列化二叉搜索树

136 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。

因此每天刷刷LeetCode非常有必要

在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode

一、题目描述

序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。

设计一个算法来序列化和反序列化 二叉搜索树 。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。

编码的字符串应尽可能紧凑。

 

示例 1:

输入:root = [2,1,3] 输出:[2,1,3]

示例 2:

输入:root = [] 输出:[]  

提示:

树中节点数范围是 [0, 104] 0 <= Node.val <= 104 题目数据 保证 输入的树是一棵二叉搜索树。

二、思路分析

1、利用前序遍历将数值存在一个数组中,然后序列化的时候加上空格分割数值,这样就完成了序列化操作

2、根据二叉搜索树的性值:中序遍历的结果是从小到大有序的,所以可以根据前序遍历的结果,获取到前序遍历的数组,然后对数组进行 sort() 排序后,就得到了中序遍历的结果数组,这样利用前序和中序遍历的结果数组,就可以和 105.从前序与中序遍历序列构造二叉树 一样的方式构建一颗二叉树。

三、代码实现

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * Encodes a tree to a single string.
 *
 * @param {TreeNode} root
 * @return {string}
 */
var serialize = function(root) {
    // 序列化操作,前序遍历,存入数组中,然后序列化的时候加上空格分割数值
    if (root === null) {
        return ''
    }
    let stringArray = []
    var postDFS = function (node) {
        if (node === null) {
            return
        }
        stringArray.push(node.val)
        postDFS(node.left)
        postDFS(node.right)
    }
    postDFS(root)
    return stringArray.join(' ') // 加入空格分割字符
};

/**
 * Decodes your encoded data to tree.
 *
 * @param {string} data
 * @return {TreeNode}
 */
var deserialize = function(data) {
    if (data.length === 0) {
        return null
    }
    let preorder = data.split(' ').map(item => {
        return Number.parseInt(item)
    })
    // 获取二叉搜索树中序遍历结果,即从小到大排好序的数组
    let inorder = [...preorder]
    inorder.sort((a, b) => {
        return a - b
    })
    
    // 根据前序遍历和中序遍历构建二叉树
    let preLen = preorder.length // 获取二叉树长度
    let inLen = inorder.length
    
    // 优化操作,建立一个 map 存储中序遍历 inorder 值对应的下标,用于根据值快速找到inorder的下标
    let map = new Map()
    for (let i = 0; i < inLen; i++) {
        map.set(inorder[i], i)
    }

    // 构建二叉树的递归函数
    const build = function (preorder, preLeft, preRight, map, inLeft, inRight) {
        // 中止条件,区间不存在值,返回空节点
        if (preLeft > preRight || inLeft > inRight) {
            return null
        }
        // 构建根节点
        let root = new TreeNode(preorder[preLeft])
        // 获取中序遍历下标,这样就能根据中序遍历的规则,知道左右子树区间长度
        let pIndex = map.get(root.val)
        // 构建左节点,传入构建完根节点后的左子树下标区间
        root.left = build(preorder, preLeft + 1, pIndex - inLeft + preLeft, map, inLeft, pIndex - 1)
        // 构建右节点,传入构建完根节点后的右子树下标区间
        root.right = build(preorder, pIndex - inLeft + preLeft + 1, preRight, map, pIndex + 1, inRight)
        return root
    }
    // 返回递归函数,传入默认值,参数值为前序遍历与中序遍历的下表区间
    return build(preorder, 0, preLen - 1, map, 0, inLen - 1)
};

/**
 * Your functions will be called as such:
 * deserialize(serialize(root));
 */

四、总结

以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~