Skip to content
Open
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
121 changes: 121 additions & 0 deletions Python3/108. Convert Sorted Array to Binary Search Tree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
## Step 1. Initial Solution

- BSTが何なのか分かっておらず、ただheight-balanced treeを作っていた
- キューに対して次に子ノードを追加するノードを入れていくことで高さをキープする
- 右が入れ終わったら左右をこのキューに入れる、という方式

```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None
root: TreeNode = TreeNode(val=nums[0])
nodes_to_add: deque[TreeNode] = deque([root])
for i in range(1, len(nums)):
node = nodes_to_add.popleft()

Choose a reason for hiding this comment

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

nodes_to_add という変数名で、同じノードを入れたり出したりしているのがわかりづらいと思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

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

nodes_to_processとかの方が良いですかね

if node.left is None:
node.left = TreeNode(val=nums[i])
nodes_to_add.append(node)
elif node.right is None:
node.right = TreeNode(val=nums[i])
nodes_to_add.append(node.left)
nodes_to_add.append(node.right)
return root

```

- 解説を読んでBSTを理解した
- 再帰で書くのがシンプル

```python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None
root: TreeNode = TreeNode()
middle: int = len(nums) // 2
root.val = nums[middle]
root.left = self.sortedArrayToBST(nums[:middle])
root.right = self.sortedArrayToBST(nums[middle+1:])
return root
```

### Complexity Analysis

- 時間計算量:O(nlogn)
- numsのコピーにO(n)の時間がかかる
- n/2のコピーが2回, n/4のコピーが4回…
- 空間計算量:O(n)
- 時間と同じオーダーかと思ったがDFSで処理していくので最大でもO(n)
- https://github.com/colorbox/leetcode/pull/38/files#r1939180637

## Step 2. Alternatives

- 基本的には二分探索と同様の選択肢の幅がある
- インデックスを管理してコピーを避ける方法
- BFSで実装したがDFSでも良い
- 当たり前だが常にheight-balancedになっている必要はない
- https://github.com/shintaro1993/arai60/pull/28/files#diff-5db3d349f04f651e2faacefca7e2937a523f2fd8c8b6cbd30ad1e7ed699f8d3aR104

```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
root: TreeNode = TreeNode()
node_and_range: deque[Tuple[TreeNode, int, int]] = deque([(root, 0, len(nums))])
while node_and_range:
node, left_index, right_index = node_and_range.popleft()
middle_index = (left_index + right_index) // 2
node.val = nums[middle_index]
Copy link

Choose a reason for hiding this comment

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

一応、numsが空配列の場合ここでIndexErrorになりますかね。別解ではNoneを返しているので意図通りかは少し気になりました

Copy link
Owner Author

Choose a reason for hiding this comment

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

空配列は問題文の条件にはないのですが、他の人のを見ると気にしていない人が多かったので書かないことにしました。

if left_index < middle_index:
node.left = TreeNode()
node_and_range.append((node.left, left_index, middle_index))
if middle_index + 1 < right_index:
node.right = TreeNode()
node_and_range.append((node.right, middle_index + 1, right_index))
return root
```

- 計算量とコード量的には再帰+インデックス管理が良さそう
- ヘルパー関数を使ったことがあまりなかったので使ってみる
- https://github.com/hayashi-ay/leetcode/pull/29/files#diff-7e1a92af8dc65ffab400b9bf2416693d15f370a5cfb6ac37e009f85a67c03a32R23

```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def sortedArrayToBSTHelper(node: TreeNode, left: int, right: int) -> TreeNode:
middle = (left + right) // 2
node.val = nums[middle]
if left < middle:
node.left = sortedArrayToBSTHelper(TreeNode(), left, middle)
if middle + 1 < right:
node.right = sortedArrayToBSTHelper(TreeNode(), middle + 1, right)
return node
return sortedArrayToBSTHelper(TreeNode(), 0, len(nums))
Copy link

Choose a reason for hiding this comment

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

TreeNode は引数で与えず中で作ってもこの場合は大丈夫でしょうかね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

本当ですね。後からreturnしてくれば先につなげなくてもいいですね

```


## Step 3. Final Solution

- ヘルパー関数が気に入った
- ノードを返してあげれば更に簡単になる
- 閉区間や開区間でも実装してみた(以下は開区間)

```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def createNode(left: int, right: int) -> TreeNode:
middle = (left + right) // 2
node = TreeNode(nums[middle])
if left + 1 < middle:
node.left = createNode(left, middle)
if middle + 1 < right:
node.right = createNode(middle, right)
return node
return createNode(-1, len(nums))
```