Conversation
| class Solution: | ||
| def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]: | ||
| def to_bst(begin: int, end: int) -> Optional[TreeNode]: | ||
| if begin == end: |
There was a problem hiding this comment.
個人的には、二分探索の終了条件は不等号もつけた方が分かりやすいと思います。
趣味の範囲かもしれません。
| def to_bst(begin: int, end: int) -> Optional[TreeNode]: | ||
| if begin == end: | ||
| return None | ||
| mid = (begin + end) // 2 |
There was a problem hiding this comment.
何となくmidは市民権を得ている感覚があったのですが、微妙ですかね。
わりとしっくり来ているのでどうしようかな...もうちょっと試して決めてみようかと思います
There was a problem hiding this comment.
mid という形容詞はありますね。
https://www.merriam-webster.com/dictionary/mid
| if not nums: | ||
| return None | ||
| sentinel = TreeNode() | ||
| parent_with_range_stack = [(sentinel, 0, len(nums), True)] |
There was a problem hiding this comment.
最初にsentinelの左側にnodeをくっつけるのがほんの少しだけ気になりました。
これやるなら最初の処理をwhileの外で行うとかですかね。
| stack.append(('back', node_ref, left_node_ref, right_node_ref, begin, end)) | ||
| stack.append(('go', left_node_ref, Box(None), Box(None), begin, mid)) | ||
| stack.append(('go', right_node_ref, Box(None), Box(None), mid + 1, end)) | ||
| node_ref.value.left = left_node_ref.value |
There was a problem hiding this comment.
ここの処理が行きがけでも行われるのが少し違和感があります。
個人的には
行き→下にTreeNodeを作るようにたのむ
帰り→下で作ったTreeNodeを繋ぎ合わせる
この方法のほうが再帰との対応が良いかと思いました。
There was a problem hiding this comment.
すみません、あまりイメージが湧かず...質問させてください。
ここの処理が行きがけでも行われるのが少し違和感があります。
これはどこの部分になるでしょうか?
行き→下にTreeNodeを作るようにたのむ
帰り→下で作ったTreeNodeを繋ぎ合わせる
もし良ければでいいんですが、コードがどんな感じになるか書いていただけないでしょうか?
There was a problem hiding this comment.
イメージこんな感じです
まあelseを足しただけですが...
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
root_ref = Box(None)
stack = [('go', root_ref, Box(None), Box(None), 0, len(nums))]
while stack:
go_back, node_ref, left_node_ref, right_node_ref, begin, end = stack.pop()
if go_back == 'go':
if begin == end:
continue
mid = (begin + end) // 2
node_ref.value = TreeNode(nums[mid])
stack.append(('back', node_ref, left_node_ref, right_node_ref, begin, end))
stack.append(('go', left_node_ref, Box(None), Box(None), begin, mid))
stack.append(('go', right_node_ref, Box(None), Box(None), mid + 1, end))
else: #go_back == 'back'
node_ref.value.left = left_node_ref.value
node_ref.value.right = right_node_ref.value
return root_ref.valueこのelseがないとgo_back === 'go'のときも左右のノードをつなげる処理が行われていて、行きと帰りで違う処理をしている理由があまりないかなと思いました。
There was a problem hiding this comment.
あーっわかりましたごめんなさい...これ if go_back == 'go' のブロックの最後にcontinue付けてるつもりでいました。
たしかにおっしゃる通り今のコードだとgoの処理でも左右につなげてますね、失礼しました 🙇
| root_ref = Box(None) | ||
| stack = [('go', root_ref, Box(None), Box(None), 0, len(nums))] | ||
| while stack: | ||
| go_back, node_ref, left_node_ref, right_node_ref, begin, end = stack.pop() |
There was a problem hiding this comment.
自分だけかもしれませんが、refが何を参照しているかが少し戸惑ったのですが、Boxを利用される場合はよくある書き方でしょうか?node, left_child, right_childとかでも良い気がしました。見当違いでしたらすみません。
There was a problem hiding this comment.
よくあるのかは分からないんですが、個人的にはPythonのような動的型付け言語で _ref の接尾辞を書かずnodeみたいに書くと、TreeNodeなのかTreeNodeを指すコンテナなのかが分からず書きにくくなる印象がありました。
| スタックに直した版。node_and_ranges_stackにappendする値を間違えており (right側で(node.right, mid, end)を積むようにしていた)、図を書くまで何が問題か分からず時間がかかった。 | ||
| こういう勘違いはこのアルゴリズムで何をしているかきちんと分かっており言語化できればあまり起こらないと思うので、理解不足なのだろう。 | ||
|
|
||
| node_and_ranges_stackはもう少しいい名前があるかも。Pythonでは問題ないがendはちょっとキーワード感あるかもしれない? |
There was a problem hiding this comment.
冗長に感じる場合、_stackは省略しても良いのかなと思いました。(好みの問題かもです。)
https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/