Skip to content

Add 108. Convert Sorted Array to Binary Search Tree.md #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
92 changes: 92 additions & 0 deletions 108. Convert Sorted Array to Binary Search Tree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# step 1

再帰で作ることを思いついた。
再帰の深さは最大で、log_2(10^4) = 4 * log_2(10) = 4 * (1 + log_2(5)) < 4 * 4 = 16。

ノードの数をnとして、
- time complexity: O(n log n)
- space complexity: O(n)

ノード数nの時の実行時間をT(n)とすると、半分に分けた問題を二つ解く + スライスのコピーで
T(n) = 2*T(n/2) + nとなる(merge sortとかと同じ形)。

```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None

middle = len(nums) // 2
left = self.sortedArrayToBST(nums[:middle])
right = self.sortedArrayToBST(nums[middle + 1:])
return TreeNode(val=nums[middle], left=left, right=right)
```

# step 2
- https://github.com/colorbox/leetcode/pull/38/files
- ダブルポインタを使った非再帰の解法あり
- https://github.com/SuperHotDogCat/coding-interview/pull/40/files#r1770559848
- > スライスを作るとコピーが発生し、処理が重くなる
- indexを追跡して行った方が処理が重くならない
- https://github.com/python/cpython/blob/c9932a9ec8a3077933a85101aae9c3ac155e6d04/Objects/listobject.c#L656
- 新しいreferenceをiterateしながら作る

ほかにもいくつか過去のプルリクを見たがあまり解法に幅がないように感じた。

stackを使った解法。step 1の時点で再帰を使ったDFSで書けているので、これも思いつきたかった。
- time complexity: O(n)
- space complexity: O(n)
```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None

root = TreeNode()
stack = [(root, 0, len(nums))]
while stack:
node, left, right = stack.pop()
middle = (left + right) // 2
node.val = nums[middle]
if left < middle:
node.left = TreeNode()
stack.append((node.left, left, middle))
if middle + 1 < right:
node.right = TreeNode()
stack.append((node.right, middle + 1, right))
return root
```

スライスを作らない再帰
- time complexity: O(n) (T(n) = 2*T(n/2) + 1)
- space complexity: O(n)
```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def index_range_to_BST(left: int, right: int) -> Optional[TreeNode]:
if not left < right:
return None

middle = (left + right) // 2
left = index_range_to_BST(left, middle)
right = index_range_to_BST(middle + 1, right)
Copy link

Choose a reason for hiding this comment

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

下でコメントされていますが、int型の引数leftをTreeNodeとしても用いるのはあまり良くないと思います。

return TreeNode(nums[middle], left, right)
return index_range_to_BST(0, len(nums))
```

# step 3
step 2ではinner関数ないでleft, rightを書き換えていたので書き換えない形でも書いた。

```python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def index_range_to_BST(left: int, right: int) -> Optional[TreeNode]:
Copy link

Choose a reason for hiding this comment

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

helperみたいな命名もありかなと思いました

if not left < right:

Choose a reason for hiding this comment

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

僕はnot使わず書いてましたが、not 使うこちらの方が直感に近いかもですね。
(自然言語で表現すると)区間が存在しないとなるので、こちらの方がすんなりくる気がしました。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。二分探索もそうですが、これとかも、区間の取り方と成立不成立によって'='がついたりつかなかったりしてややこしいので、notを入れて統一するのが好みかもしれません

Choose a reason for hiding this comment

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

わかります。探索アルゴリズムのグリッド範囲外判定とかも not でやりたい気持ちです。

Copy link

Choose a reason for hiding this comment

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

ここらへんは趣味かと思います。私は、left >= right と左が大きいときには否定的な意味としています。

return None

middle = (left + right) // 2
left_node = index_range_to_BST(left, middle)
right_node = index_range_to_BST(middle + 1, right)
return TreeNode(nums[middle], left_node, right_node)
return index_range_to_BST(0, len(nums))
```