持续创作,加速成长!这是我参与「掘金日新计划 · 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));
*/
四、总结
以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~