Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@

## 再帰による解答
---
### 1~3回目
12m25s<br>
preorder, inorderについて考えていたためか、整理できた。
本番でこの問題を緊張感の中で解けるかはあまり自信がない。
変数が少なく、2~3回目において大きな変更はなし。
時間計算量: O(N)<br>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

中で.indexで舐めてるので0(N^2)でしょうか。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preorder と inorder のスライスでコピーが作られるので、木が片側に偏っている場合にも O(N2) になると思います。

空間計算量: O(N)<br>

```python
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if not preorder or not inorder:
return None
root = TreeNode(preorder[0])
index_in_inorder = inorder.index(preorder[0])
root.left = self.buildTree(preorder[1:index_in_inorder+1], inorder[:index_in_inorder])
root.right = self.buildTree(preorder[index_in_inorder+1:], inorder[index_in_inorder+1:])

return root
```

### stackを利用した解法
```python
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if not preorder or not inorder:
return None

root = TreeNode(preorder[0])
nodes_with_index = [(root, 0, len(inorder) - 1, 0, len(preorder) - 1)]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

閉開区間で書いてもよいかと思いました

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

要素の数が多く、どれが何を表すか分かりにくく感じました。 dataclass や namedtuple などを用いて、各要素に名前 (変数名) を付けてあげたほうが良いと思います。

inorder_index_map = {value: index for index, value in enumerate(inorder)}

while nodes_with_index:
node, in_start, in_end, pre_start, pre_end = nodes_with_index.pop()
if pre_start > pre_end or in_start > in_end:
continue

root_val = preorder[pre_start]
mid = inorder_index_map[root_val]
left_count = mid - in_start
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right_count を定義しておきます?
そうすると、
right_count > 0
pre_end - right_count + 1
かなんかでいけます。

Copy link
Copy Markdown
Owner Author

@Mike0121 Mike0121 May 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。確かにそっちの方が読みやすいですね。
right_countを定義した解法を追記しました。


if left_count > 0:
left_node = TreeNode(preorder[pre_start + 1])
node.left = left_node
nodes_with_index.append((left_node, in_start, mid - 1, pre_start + 1, pre_start + left_count))

if mid < in_end:
right_node = TreeNode(preorder[pre_start + left_count + 1])
node.right = right_node
nodes_with_index.append((right_node, mid + 1, in_end, pre_start + left_count + 1, pre_end))

return root
```

right_countを定義して利用
変数名: root_val → node_val
```python
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if not preorder or not inorder:
return None

root = TreeNode(preorder[0])
nodes_with_index = [(root, 0, len(inorder) - 1, 0, len(preorder) - 1)]
inorder_index_map = {value: index for index, value in enumerate(inorder)}

while nodes_with_index:
node, in_start, in_end, pre_start, pre_end = nodes_with_index.pop()
if pre_start > pre_end or in_start > in_end:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

80行目や85行目の判定からこの条件を満たすものしかstackに積んでないことが分かるのでこの条件は不要だと思いました。

continue

node_val = preorder[pre_start]
mid = inorder_index_map[node_val]
left_count = mid - in_start
right_count = in_end - mid

if left_count > 0:
left_node = TreeNode(preorder[pre_start + 1])
node.left = left_node
nodes_with_index.append((left_node, in_start, mid - 1, pre_start + 1, pre_start + left_count))

if right_count > 0:
right_node = TreeNode(preorder[pre_start + left_count + 1])
node.right = right_node
nodes_with_index.append((right_node, mid + 1, in_end, pre_start + left_count + 1, pre_end))

return root
```

## HashMapを用いた解法
---
ahayashiさん、kandaさんの解答を参考に、HashMapと関数化を利用した解答も書きました。
```python
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
def buildtree_helper(left_bound, right_bound):
nonlocal preorder_index
if left_bound >= right_bound:
return

root_value = preorder[preorder_index]
root = TreeNode(root_value)

inorder_index = inorder_value_to_index[root_value]
preorder_index += 1
root.left = buildtree_helper(left_bound, inorder_index)
root.right = buildtree_helper(inorder_index + 1, right_bound)
return root

preorder_index = 0
inorder_value_to_index = {}
for index, value in enumerate(inorder):
inorder_value_to_index[value] = index
Comment on lines +113 to +116
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

関数内で使う変数は、関数の定義の前に書いてあった方が個人的には読みやすいです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます、ご指摘の通りですね。
今回は関数の中でnonlocalでpreorder_indexにアクセスしたり、ハッシュマップを使っているので余計そうかもしれません。


return buildtree_helper(0, len(inorder))
```