Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions 0297.Serialize-and-Deserialize-Binary-Tree/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 297. Serialize and Deserialize Binary Tree

## step1

37mぐらいかかった。確実に解けると思ったが、スラスラと書くことができなかった。

幅優先探索で解くことにした。

間違えた点:
- delimをつけずに間違えた(数字が2桁だとdecodeできない)
- deserializeでキューになぜかNoneを入れた


## step2

https://support.leetcode.com/hc/en-us/articles/32442719377939-How-to-create-test-cases-on-LeetCode#h_01J5EGREAW3NAEJ14XC07GRW1A

こんなサイトがあることを知らなかった。level order traversalという名前がついていたんだった。

探索順は同じだが、serializeした文字列がこちらの方が短い。nullの場合の処理が異なる。

この場合、自身をresultに入れてから、子をresultに入れるとかける: step2

こちらも書くのに20mぐらいかかった。

書きながら注意したことで、以下は正しく動かない。

```python
child = node.left
child = TreeNode(0)
```

これはPythonの変数がオブジェクトの参照であるためで、childが単に`TreeNode(0)`オブジェクトを指すようになる、という変更になる。

## 他の解法

LeetCodeの与えられ方に引きずられて、level-orderを最初に選択したが、DFSでも解くことができるはず。

11mぐらいでかけた。

Pre-orderとPost-orderは可能だが、In-orderは可能なのか?おそらく不可能だと思う。理由は、in-orderだとnull Nodeがある場合に根の位置が特定できないから。


LeetCodeのSolutionを検索すると in-order と書かれているものがあったが、コードを読むと実際にはpre-orderであった。
https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solutions/6678162/in-order-traversal-simple-solution-by-th-822j/?envType=problem-list-v2&envId=rab78cw1



## 他の人のコード

https://github.com/hayashi-ay/leetcode/pull/74

> 書いてみた感想として、探索だけならDFSもBFSもそこまで書きやすさは変わらないですが、Treeの構築が発生する場合はBFSおよびDFSのループだと書きにくいなと思いました。親ノードや左右どちらにつなぐかなどを考えないといけないので。

確かに自分もBFSで書くので苦戦し、再帰DFSで書くと簡単にかけた

自分はindexを使ったが、iteratorを使っている。例外で処理しようとしたが、nextの引数defaultを勧められている。nextの引数defaultは知らなかった。

https://docs.python.org/3/library/functions.html#next

https://github.com/shining-ai/leetcode/pull/62

> イテレータを使う発想がありませんでした。

自分も同じく。

https://github.com/potrue/leetcode/pull/73

## step3
最も個人的に自然な pre-orderを書いておく
77 changes: 77 additions & 0 deletions 0297.Serialize-and-Deserialize-Binary-Tree/step1_level_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import collections


# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Codec:
NO_NODE = "n"
DELIM = ","

def serialize(self, root: TreeNode | None) -> str:
"""Encodes a tree to a single string."""
if root is None:
return self.NO_NODE

frontier = collections.deque([root])
result = []

while frontier:
node = frontier.popleft()
if node is None:
result.append(self.NO_NODE)
continue

result.append(str(node.val))
frontier.append(node.left)
frontier.append(node.right)

return self.DELIM.join(result)

def _create_node(self, c: str) -> TreeNode | None:
if c == self.NO_NODE:
return None
return TreeNode(int(c))

def deserialize(self, data: str) -> TreeNode | None:
"""Decodes your encoded data to tree."""
if not data or data == self.NO_NODE:
return None

tokens = data.split(self.DELIM)

root = self._create_node(tokens[0])
frontier = collections.deque([root])

i = 1
while i < len(tokens):
node = frontier.popleft()

if node is None:
continue

node.left = self._create_node(tokens[i])
if node.left:
frontier.append(node.left)
i += 1

if i >= len(tokens):
continue

node.right = self._create_node(tokens[i])
if node.right:
frontier.append(node.right)
i += 1

return root


# Your Codec object will be instantiated and called as such:
# ser = Codec()
# deser = Codec()
# ans = deser.deserialize(ser.serialize(root))
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import collections


# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Codec:
NO_NODE = "n"
DELIM = ","

def serialize(self, root: TreeNode | None) -> str:
"""Encodes a tree to a single string."""
if root is None:
return self.NO_NODE

result = [str(root.val)]
frontier = collections.deque([root])

while frontier:
node = frontier.popleft()
for child in (node.left, node.right):
if child is not None:
result.append(str(child.val))
frontier.append(child)
else:
result.append(self.NO_NODE)

while result and result[-1] == self.DELIM:
result.pop()

return self.DELIM.join(result)

def deserialize(self, data: str) -> TreeNode | None:
"""Decodes your encoded data to tree."""
if not data or data == self.NO_NODE:
return None

tokens = data.split(self.DELIM)

root = TreeNode(tokens[0])
frontier = collections.deque([root])

i = 1
while i < len(tokens):
node = frontier.popleft()

for child_name in ("left", "right"):
if tokens[i] != self.NO_NODE:
child = TreeNode(tokens[i])
setattr(node, child_name, child)
frontier.append(child)
i += 1
if i >= len(tokens):
break

return root
50 changes: 50 additions & 0 deletions 0297.Serialize-and-Deserialize-Binary-Tree/step2_postorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Codec:
NO_NODE = "n"
DELIM = ","

def serialize(self, root: TreeNode | None) -> str:
"""Encodes a tree to a single string."""
result = []

def traverse(node):
if node is None:
result.append(self.NO_NODE)
return

traverse(node.left)
traverse(node.right)
result.append(str(node.val))

traverse(root)
return self.DELIM.join(result)

def deserialize(self, data: str) -> TreeNode | None:
"""Decodes your encoded data to tree."""
if not data or data == self.NO_NODE:
return None

tokens = data.split(self.DELIM)

def traverse() -> TreeNode | None:
if not tokens:
return None

token = tokens.pop()
if token == self.NO_NODE:
return None

node = TreeNode(token)
node.right = traverse()
node.left = traverse()

return node

return traverse()
55 changes: 55 additions & 0 deletions 0297.Serialize-and-Deserialize-Binary-Tree/step2_preorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None


class Codec:
NO_NODE = "n"
DELIM = ","

def serialize(self, root: TreeNode | None) -> str:
"""Encodes a tree to a single string."""
result = []

def traverse(node):
if node is None:
result.append(self.NO_NODE)
return

result.append(str(node.val))
traverse(node.left)
traverse(node.right)

traverse(root)
return self.DELIM.join(result)

def deserialize(self, data: str) -> TreeNode | None:
"""Decodes your encoded data to tree."""
if not data or data == self.NO_NODE:
return None

tokens = data.split(self.DELIM)

i = 0

def traverse():
nonlocal i

if i >= len(tokens):
return None

if tokens[i] == self.NO_NODE:
i += 1
return

node = TreeNode(tokens[i])
i += 1
node.left = traverse()
node.right = traverse()

return node

return traverse()
50 changes: 50 additions & 0 deletions 0297.Serialize-and-Deserialize-Binary-Tree/step3_preorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None


class Codec:
NO_NODE = "n"
DELIM = ","

def serialize(self, root: TreeNode | None) -> str:
"""Encodes a tree to a single string."""
result = []

def traverse(node):
if node is None:
result.append(self.NO_NODE)
return
result.append(str(node.val))
traverse(node.left)
traverse(node.right)

traverse(root)
while result and result[-1] == self.NO_NODE:
result.pop()

return self.DELIM.join(result)

def deserialize(self, data: str) -> TreeNode | None:
"""Decodes your encoded data to tree."""
if not data or data == self.NO_NODE:
return None

tokens = data.split(self.DELIM)
token_iterator = iter(tokens)

def traverse():
token = next(token_iterator, None)
if token is None or token == self.NO_NODE:
return None

node = TreeNode(int(token))
node.left = traverse()
node.right = traverse()

return node

return traverse()