首页 > 其他 > 详细

leetcode之297二叉树的序列化与反序列化Golang

时间:2020-11-22 12:58:17      阅读:24      评论:0      收藏:0      [点我收藏+]

题目描述

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

示例:

你可以将以下二叉树:

    1
   /   2   3
     /     4   5

序列化为 "[1,2,3,null,null,4,5]"

提示: 这与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

说明: 不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。

算法

其实这道题使用深度优先遍历和宽度优先遍历都可以,只要保证了二叉树的结构信息就可以了,而我采用的就是宽度优先遍历,而我第一次提交超时的原因是保存二叉树结构信息的时候,多保存了一下空的结点信息,例如对于如下二叉树

         1
       /      2       3
   / \      /  nil nil   4   5
 /     \         nil     nil     6

对于上面的二叉树,我超时的时候,我保存的是一颗完全二叉树,也就是说,第三层没有结点的地方,我用了一个null保存,所以导致了超时,为了不超时,我就不保存这些信息,只保存父节点不为空的结点。

序列化方式:

采用层序遍历的方式,一层一层的读取结点:

  • 遍历当前层的所有结点,如果当前结点为空结点,那么就向结果中加入null
  • 如果当前结点不为空,那么就向结果中加入结点的值,并且将当前结点的子结点加入下一层应该遍历的结点,如果子结点为空,那么就传入nil
  • 当某一层全部为空节点,说明了序列化二叉树就已经结束了,返回结果

序列化方式:

遍历传入的字符串,字符串按照逗号,进行分割,得到字符串切片

  • 遍历字符串切片
  • 首先处理根结点,如果根节点为空,那么就直接返回nil
  • 根结点作为单独的一层,按照层序遍历,遍历每一层的结点
    • 如果当前结点为空,那么说明这个空结点不可能会有子节点,所以直接遍历当前层的下一个结点
    • 如果当前结点不为空,那么进入内层循环,这个循环会循环两侧,分别构建当前的左孩子和右孩子
    • 每次构建一个孩子以后,就判断是否已经使用完入口参数的所有字符串切片中的数据,如果使用完了就返回二叉树

代码

// TreeNode ...
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

// Codec ...
type Codec struct {
}

// Constructor ...
func Constructor() Codec {
	return Codec{}
}

func (c *Codec) serizalize(root *TreeNode) string {
	// 也就是二叉树的层序遍历,因为只有这样才能保存二叉树的结构信息
	if root == nil {
		return "null,"
	}
	res := ""
	que := []*TreeNode{root}
	for {
		tmpQue := []*TreeNode{}
		for _, nodeV := range que {
			if nodeV == nil {
				res += "null,"
			} else {
				value := strconv.Itoa(nodeV.Val)
				res = res + value + ","
				if nodeV.Left != nil {
					tmpQue = append(tmpQue, nodeV.Left)
				} else {
					tmpQue = append(tmpQue, nil)
				}
				if nodeV.Right != nil {
					tmpQue = append(tmpQue, nodeV.Right)
				} else {
					tmpQue = append(tmpQue, nil)
				}
			}
		}
		nilFlag := false
		for _, nodeT := range tmpQue {
			if nodeT != nil {
				nilFlag = true
				break
			}
		}
		if !nilFlag {
			break
		}
		que = tmpQue
	}
	return res
}

func (c *Codec) deserialize(data string) *TreeNode {
	nodeVs := strings.Split(data, ",")
	nodeVs = nodeVs[:len(nodeVs)-1]
	if len(nodeVs) == 0 {
		return nil
	}
	if nodeVs[0] == "null" {
		return nil
	}
	rootVal, _ := strconv.Atoi(nodeVs[0])
	root := &TreeNode{
		Val: rootVal,
	}
	count := 1
	que := []*TreeNode{root}
	if count == len(nodeVs) {
		return root
	}
	for {
		tmpQue := []*TreeNode{}
		for _, tmpNode := range que {
			if tmpNode == nil {
				continue
			}
			// 每个结点有左右两个孩子
			for i := 0; i < 2; i++ {
				var node *TreeNode
				if nodeVs[count] != "null" {
					nodeV, _ := strconv.Atoi(nodeVs[count])
					node = &TreeNode{Val: nodeV}
				}
				if i == 0 {
					tmpNode.Left = node
				} else {
					tmpNode.Right = node
				}
				tmpQue = append(tmpQue, node)
				if count++; count == len(nodeVs) {
					return root
				}
			}
		}
		que = tmpQue
	}
}

leetcode之297二叉树的序列化与反序列化Golang

原文:https://www.cnblogs.com/gyyyl/p/14018720.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!