leetcode刷题记录:二叉树04(序列化和反序列化)

参考:https://labuladong.online/algo/data-structure/serialize-and-deserialize-binary-tree/

1. 前中后序和二叉树的唯一性

  • 给定空指针的前提下,只有前序和后序可以唯一确定一颗二叉树;中序不可以。原因是中序遍历无法确定二叉树根节点的位置。
  • 不给定空指针的前提下,只靠一种遍历结果是无法还原二叉树的;
    给定前序和中序,或者中序和后序可以还原;只给前序和后序是无法唯一还原的。

2. leetcode 297 二叉树的序列化和反序列化

https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/

2.1 前序遍历解法

先把序列化结果存在数组res中,再通过逗号拼接,这样写起来比较简洁。

  • 序列化:需要外部变量和辅助函数。将根节点加入数组,剩下的交给递归。
    这里注意,也可以不用外部变量,用分解的方式来做。每次递归的时候是res.extend(self.serializeHelper(root.left)). 但是尽量避免这种数组操作,避免内存开销过大。
  • 反序列化:前序是从左向右,所以先构造根节点,然后递归地构造左右子树。和序列化的写法是对称的。
    注意需要判断节点值是否为‘#’
class Codec:
    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        self.res = [] # 新建一个外部变量,存放序列化的结果
        self.serializeHelper(root)
        return ','.join(self.res)
    def serializeHelper(self, root):
        if not root:
            self.res.append('#')
            return
        self.res.append(str(root.val)) # 每次把根节点append到res里,其余的交给递归
        self.serializeHelper(root.left)
        self.serializeHelper(root.right)
        
    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        return self.deserializeHelper(data.split(','))

    def deserializeHelper(self, arr):
        if not arr:
            return
        rootValue = arr.pop(0) # 和序列化类似,每次把最左边的根节点出队加入root,其余的交给递归
        if rootValue == '#':
            return
        root = TreeNode(int(rootValue))
        root.left = self.deserializeHelper(arr)
        root.right = self.deserializeHelper(arr)
        return root

2.2 后序遍历解法

序列化部分和前序类似;
反序列化部分,先构造根节点,然后递归地构造左右子树。注意因为后序是从右到左,所以要先构造右子树,再构造左子树

class Codec:

    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        self.res = []
        self.serializeHelper(root)
        return ','.join(self.res)
    def serializeHelper(self, root):
        if not root:
            self.res.append('#')
            return
        self.serializeHelper(root.left)
        self.serializeHelper(root.right)
        self.res.append(str(root.val))

        
    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        return self.deserializeHelper(data.split(','))
        
    def deserializeHelper(self, arr):
        if not arr:
            return
        rootValue = int(arr.pop(-1))
        if rootValue == '#':
            return 
        root = TreeNode(rootValue)
        root.right = self.deserializeHelper(arr)
        root.left = self.deserializeHelper(arr)
        return root

2.3 层序遍历解法

  • 序列化比较简单,根据层序遍历做一些改动即可;
  • 反序列化,使用指针i代表node的子节点。每构建一个子节点,i向后移一位。
  • 循环条件可以写成while q,也可以写成 while i < len(nodes), 两者是等价的
class Codec:

    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        if not root:
            return '#'
        q = deque()
        q.append(root)
        res = []
        while q:
            sz = len(q)
            for i in range(sz):
                cur = q.popleft()
                if not cur:
                    res.append('#')
                else:
                    res.append(str(cur.val))
                    q.append(cur.left)
                    q.append(cur.right)
        # print(res)
        return ','.join(res)

        

    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        if not data:
            return
        nodes = data.split(',')
        if nodes[0] == '#':
            return 
        root = TreeNode(int(nodes[0]))
        q = deque([root])
        i = 1
        while q: # 等价于while i < len(nodes)
            node = q.popleft()
            if (nodes[i] != '#'):
                node.left = TreeNode(int(nodes[i]))
                q.append(node.left)
            i += 1
            if (i < len(nodes) and nodes[i] != '#'):
                node.right = TreeNode(int(nodes[i]))
                q.append(node.right)
            i += 1
        return root

3. 序列化的应用:寻找重复的子树

https://leetcode.cn/problems/find-duplicate-subtrees/description/
思路:对于某个节点,需要知道两件事:

  • 以本节点为根节点的子树长什么样子。即本节点+左右子树的样子,可以用二叉树的序列化来描述。
  • 其他子树长什么样子:遍历所有的节点,对每个节点都用序列化的形式记录下来,存放在一个HashMap里。map的key是序列化后的字符串,value是出现的次数。
  • res 赋值的条件:freq 严格等于1(不是大于1否则res中的子树会重复)
class Solution(object):
    def __init__(self):
        self.subTrees = {}
        self.res = []
    def findDuplicateSubtrees(self, root):
        """
        :type root: TreeNode
        :rtype: List[TreeNode]
        """
        self.serialize(root)
        return self.res
    def serialize(self, root):
        if not root:
            return '#'
        left = self.serialize(root.left)
        right = self.serialize(root.right)
        rootStr = left + ',' + right + ',' + str(root.val)
        freq = self.subTrees.get(rootStr, 0)
        if freq == 1: # 注意,freq = 1时说明已经有一个相同结构的子树了,此时res中添加root。
            self.res.append(root)
        self.subTrees[rootStr] = freq + 1
        return rootStr

你可能感兴趣的:(2024算法工程师求职,leetcode,linux,算法)