• 【LeetCode】二叉树的序列化和反序列化(dfs/bfs)


    二叉树的序列化和反序列化

    题目链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/

    题目大意:写两个函数,能够分别对二叉树进行序列化和反序列化

    方法1:bfs

    序列化:采用队列实现,根节点先入队,处理时按照左孩子右孩子的顺序处理

    func (this *Codec) serialize(root *TreeNode) string {
    	// 序列化
    	var queue []*TreeNode
    	var result []string
    	
    	// 根节点先入队
    	queue=append(queue,root)
    
    	// 持续处理,知道队列中没有元素
    	for len(queue)!=0{
    		// 取出队列头部元素
    		node:=queue[0]
    		queue=queue[1:]
    
    		// 此元素不空,输出值并将其左右孩子入队
    		if node!=nil{
    			result=append(result,strconv.Itoa(node.Val))
    			queue=append(queue,node.Left)
    			queue=append(queue,node.Right)
    		}else {
    			// 此元素空,输出空标志符
    			result=append(result,"x")
    		}
    	}
    
    	// 分隔符连接
    	return strings.Join(result,",")
    }
    

    反序列化:同样利用队列,用队列来构建节点的孩子,入队的节点都代表需要根据字符串来构建他们的孩子

    // 反序列化
    func (this *Codec) deserialize(data string) *TreeNode {
    	// 特殊情况 root就是空
    	if data=="x"{
    		return nil
    	}
    
    	// 根据分隔符得到字符串数组,每个字符串都是一个节点的值
    	ans:=strings.Split(data,",")
    
    	var queue []*TreeNode
    	
    	// 构建根节点,并将其入队
    	rootVal,_:=strconv.Atoi(ans[0])
    	root:=&TreeNode{
    		Val:   rootVal,
    	}
    	queue=append(queue,root)
    
    	// 指示器,指向的地方代表当前节点的左孩子节点值
    	c:=1
    
    	for c<len(ans){
    		// 分别取当前节点的左右孩子值
    		leftStr:=ans[c]
    		rightStr:=ans[c+1]
    
    		// 取出队列头部元素作为当前节点
    		node:=queue[0]
    		queue=queue[1:]
    
    		// 左孩子值非空
    		if leftStr!="x"{
    			
    			// 构建左孩子,并连接左孩子和当前节点,并将左孩子入队,以便后续构造左孩子的孩子
    			leftVal,_:=strconv.Atoi(leftStr)
    			leftNode:=&TreeNode{
    				Val:   leftVal,
    			}
    			node.Left=leftNode
    			queue=append(queue,leftNode)
    		}
    
    		// 右孩子值非空
    		if rightStr!="x"{
    			// 构建右孩子,并连接右孩子和当前节点,并将右孩子入队,以便后续持续构造右孩子的孩子
    			rightVal,_:=strconv.Atoi(rightStr)
    			rightNode:=&TreeNode{
    				Val:   rightVal,
    			}
    			node.Right=rightNode
    			queue=append(queue,rightNode)
    		}
    
    		// 每次前进两步,因为一次处理了当前节点的左孩子和右孩子
    		c+=2
    	}
    	
    	return root
    }
    

    方法2:dfs

    序列化

    // 得到root的序列化结果
    func dfs1(root *TreeNode) string{
    	if root==nil{
    		return "x"
    	}
    
    	// 分别得到root左右子树的序列化结果
    	leftStr:=dfs1(root.Left)
    	rightStr:=dfs1(root.Right)
    
    	// 按照先序遍历的形式,拼接序列化结果
    	return strconv.Itoa(root.Val)+ ","+leftStr+","+rightStr
    }
    // Serializes a tree to a single string.
    func (this *Codec) serialize(root *TreeNode) string {
    	return dfs1(root)
    }
    

    反序列化

    // 根据字符串数组构建树
    func dfs2(list *[]string) *TreeNode{
    	// 特殊情况,数组里没东西,返回nil
    	if len(*list)==0{
    		return nil
    	}
    
    	// 去数组首个元素
    	rootStr:=(*list)[0]
    	*list=(*list)[1:]
    
    	// 如果此元素是空标志符的话,也是返回nil
    	if rootStr=="x"{
    		return nil
    	}
    
    	// 构建root
    	rootVal,_:=strconv.Atoi(rootStr)
    	root:=&TreeNode{
    		Val:   rootVal,
    	}
    	// 通过递归分别构建root左右子树
    	root.Left=dfs2(list)
    	root.Right=dfs2(list)
    
    
    	return root
    }
    // 反序列化
    func (this *Codec) deserialize(data string) *TreeNode {
    	ans:=strings.Split(data,",")
    	return dfs2(&ans)
    }
    

    上述两种方法,其时间复杂度和空间复杂度都是O(N),性能上没有什么区别,只是两种不同的解题思想而已

  • 相关阅读:
    常用模块
    递归函数
    内置函数与匿名函数
    Mac控制台相关操作
    Maven相关知识记录
    @Import底层实现原理
    spring循环依赖
    springcloud注册中心对比
    分布式事务
    Drools使用注意事项
  • 原文地址:https://www.cnblogs.com/yinbiao/p/16113732.html
Copyright © 2020-2023  润新知