二叉树的序列化和反序列化
剑指 Offer II 048. 序列化与反序列化二叉树 - 力扣(Leetcode)
介绍
一道经典的序列化题目,题目给的是二叉树的结构,我们需要将二叉树的结构转换为字符串,再转换回去
基本思路是使用前序遍历,把结果以字符串形式存储起来。(存储结构很重要)
第一版的算法为
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
type Codec struct {
}
func Constructor() (_ Codec) {
return
}
// Serializes a tree to a single string.
func (this *Codec) serialize(root *TreeNode) string {
if root==nil {return ""}
k :=root
s:=""
s+=string(k.Val)
s+=dfs(k.Left)
s+=dfs(k.Right)
return s
}
func dfs(root *TreeNode) string{
if root==nil{return "#"}
s:=""
k:=root
s+=string(k.Val)
s+=dfs(k.Left)
s+=dfs(k.Right)
return s
}
// Deserializes your encoded data to tree.
func (this *Codec) deserialize(data string) *TreeNode {
if data=="" {return nil}
root:=&TreeNode{0,nil,nil}
var num *int
k:=0
num = &k
s:=data[*num]
if s=='#'{ return nil}
root.Val=int(s)
root.Left=sdfs(data,num)
root.Right=sdfs(data,num)
return root
}
func sdfs(data string,num *int) *TreeNode{
*num+=1
if *num>=len(data){return nil}
root:=&TreeNode{0,nil,nil}
s:=data[*num]
if s=='#'{return nil}
root.Val=int(s)
root.Left=sdfs(data,num)
root.Right=sdfs(data,num)
return root
}
/**
* Your Codec object will be instantiated and called as such:
* ser := Constructor();
* deser := Constructor();
* data := ser.serialize(root);
* ans := deser.deserialize(data);
*/
交上去发现错了,错误案例为
[4,-7,-3,null,null,-9,-3,9,-7,-4,null,6,null,-6,-6,null,null,0,6,5,null,9,null,null,-1,-4,null,null,null,-2]
思考了一下为什么,我这里存储是把null和数字都当成一个字符存进去,即存成4-7-3##等等,使得我每次读数的时候只能读一个字符,所以遇到负数则会出现问题。
那么代码可以改为在字符串中添加 ‘,’,然后用split()方法来抽离。
修改后的代码为
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
type Codec struct {}
func Constructor() (_ Codec) {
return
}
// Serializes a tree to a single string.
func (this *Codec) serialize(root *TreeNode) string {
if root==nil {return ""}
k :=root
s:=""
s+=strconv.Itoa(k.Val)
s+=dfs(k.Left)
s+=dfs(k.Right)
return s
}
func dfs(root *TreeNode) string{
if root==nil{return ",#"}
s:=""
k:=root
s+=","+strconv.Itoa(k.Val)
s+=dfs(k.Left)
s+=dfs(k.Right)
return s
}
// Deserializes your encoded data to tree.
func (this *Codec) deserialize(data string) *TreeNode {
if data=="" {return nil}
root:=&TreeNode{0,nil,nil}
var num *int
k:=0
num = &k
h:=strings.Split(data,",")
s:=h[*num]
if s=="#"{ return nil}
root.Val,_=strconv.Atoi(s)
root.Left=sdfs(data,num,h)
root.Right=sdfs(data,num,h)
return root
}
func sdfs(data string,num *int,h []string) *TreeNode{
*num+=1
root:=&TreeNode{0,nil,nil}
if *num>=len(h){return nil}
s:=h[*num]
if s=="#"{return nil}
root.Val,_=strconv.Atoi(s)
root.Left=sdfs(data,num,h)
root.Right=sdfs(data,num,h)
return root
}
/**
* Your Codec object will be instantiated and called as such:
* ser := Constructor();
* deser := Constructor();
* data := ser.serialize(root);
* ans := deser.deserialize(data);
*/
答案过了,那么这个代码的问题有哪些
- 位于全局的多余的dfs和sdfs
- 代码的长度,耦合度高
- 运行速度较慢(击败“47%”)
- 多余的空间复杂度
那么我们就可以根据以上方法进行优化,拼接字符串也可以使用strings来实现
官方解:
type Codec struct{}
func Constructor() (_ Codec) {
return
}
func (Codec) serialize(root *TreeNode) string {
sb := &strings.Builder{}
var dfs func(*TreeNode)
dfs = func(node *TreeNode) {
if node == nil {
sb.WriteString("null,")
return
}
sb.WriteString(strconv.Itoa(node.Val))
sb.WriteString(",")
dfs(node.Left)
dfs(node.Right)
}
dfs(root)
return sb.String()
}
func (Codec) deserialize(data string) *TreeNode {
sp := strings.Split(data, ",")
var build func() *TreeNode
build = func() *TreeNode {
if sp[0] == "null" {
sp = sp[1:]
return nil
}
val, _ := strconv.Atoi(sp[0])
sp = sp[1:]
return &TreeNode{val, build(), build()}
}
return build()
}
终解
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
type Codec struct {
}
func Constructor() (_ Codec) {
return
}
// Serializes a tree to a single string.
func (this *Codec) serialize(root *TreeNode) string {
sb := &strings.Builder{}
var dfs func(*TreeNode)
dfs =func(root *TreeNode){
if root==nil{
sb.WriteString("null,")
return
}
sb.WriteString(strconv.Itoa(root.Val))
sb.WriteString(",")
dfs(root.Left)
dfs(root.Right)
}
dfs(root)
return sb.String()
}
// Deserializes your encoded data to tree.
func (this *Codec) deserialize(data string) *TreeNode {
s := strings.Split(data, ",")
var dfs func() *TreeNode
dfs = func() *TreeNode {
if s[0] == "null" {
s = s[1:]
return nil
}
node := &TreeNode{0, nil, nil}
val, _ := strconv.Atoi(s[0])
node.Val = val
s = s[1:]
node.Left = dfs()
node.Right = dfs()
return node
}
return dfs()
}
/**
* Your Codec object will be instantiated and called as such:
* ser := Constructor();
* deser := Constructor();
* data := ser.serialize(root);
* ans := deser.deserialize(data);
*/
Q.E.D.