Skip to content

108. Convert Sorted Array to Binary Search Tree#26

Open
TORUS0818 wants to merge 1 commit intomainfrom
108
Open

108. Convert Sorted Array to Binary Search Tree#26
TORUS0818 wants to merge 1 commit intomainfrom
108

Conversation

@TORUS0818
Copy link
Copy Markdown
Owner

# self.right = right
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
# complete binary tree
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コメントで関数名の補足わかりやすいです。

# self.right = right
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
left, mid, right = 0, len(nums) // 2, len(nums)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

好みかもしれませんが、3変数横並びだと少し認知負荷あるかと思いました。
midは次の行でも良い気もします。

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.

確かに演算も入っているし見にくかったかもしれませんね。。
ありがとうございます!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

野田さんから以下のようなコメントをもらったことがあるので、ただの代入であればそれぞれで宣言したほうがよいかもです。

thonda28/leetcode#3 (comment)


時間計算量:O(N)

空間計算量:O(NlogN)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

空間計算量 O(N log N) でしょうか…?

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.

考え方間違ってたらすみません。以下のように考えました。

再帰1回目:
nums[:root_value_index]nums[root_value_index + 1:]でサイズN-1のコピーが発生
再帰2回目:
同様にサイズN-2のコピーが発生
...
再帰k回目:
同様にサイズN-kのコピーが発生

k=logNなので、\sum_{i=1}^k (N-i) = kN - \frac{k(k+1)}{2} = NlogN - \frac{logN(logN+1)}{2}

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.

あ、減る数が違いますね。。

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.

毎回N-(2^k-1)のコピーが発生して、
\sum_{i=1}^k (N-(2^i-1)) = Nk + k + 2(2^k-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.

再帰 1 回目: N / 2
再帰 2 回目: N / 4
再帰 3 回目: N / 8
...
で、 N / 2 + N / 4 + N / 8 + ... <= N だと思いました。

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.

あ、ようやく理解しました。
私はleftとrightを並列で計算してましたね。。

nums_queue = deque(nums)
def set_values(cbt_root: Optional[TreeNode]) -> None:
nodes = [cbt_root]
while nodes:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これnodesとwhileいらなくないでしょうか?
nodesにcbt_root以外入らないような気がしてます

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.

ご明察です。

書き直しました。

# 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]:
        # complete binary tree
        def build_cbt(index: int):
            if index >= len(nums):
                return None
            root = TreeNode()
            root.left = build_cbt(2 * index + 1)
            root.right = build_cbt(2 * index + 2)
            return root
        
        nums_queue = deque(nums)
        def set_values(cbt_root: Optional[TreeNode]) -> None:
            if not cbt_root:
                return None
            set_values(cbt_root.left)
            cbt_root.val = nums_queue.popleft()
            set_values(cbt_root.right)

        cbt_root = build_cbt(0)
        set_values(cbt_root)

        return cbt_root


計算量:nums.length=Nとして、

時間計算量:O(N)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

各レベルでO(n/2)のコピーコストが発生して、O(n log n)になりませんか?

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.

なんだかよく分からなくなってしまいました。。
時間がO(NlogN)で空間がO(N)でしょうか?
#26 (comment)

ちょっと考えます。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コピーコストの部分は
#26 (comment)
と同様、

再帰 1 回目: N / 2
再帰 2 回目: N / 4
再帰 3 回目: N / 8
...
で、 N / 2 + N / 4 + N / 8 + ... <= N だと思いました。

で、 O(N) だと思いました。

Copy link
Copy Markdown

@nodchip nodchip Jul 26, 2024

Choose a reason for hiding this comment

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

上のコメント間違えました。 @kazukiii さんのおっしゃる通り、各レベル k で N / 2^k * 2^k = N のコピーコストが発生し、レベルの数が log N なので、O(N log N) だと思います。

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.

纏めると、
時間計算量:0(NlogN)
空間計算量:0(N)

インデックス管理方式にすると
時間計算量:0(N)
空間計算量:0(logN)

ですかね。

class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def build_bst(left: int, right: int):
if left >= right:
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がleftより左に来ることはないので、個人的にはleft == rightと書きたくなりますが、
ここの部分どう考えているか知りたいです。

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.

あまり深い拘りはないのですが、どこかのコメントでこちらの書き方の方が親和性があるとあったので採用しました。

確かにleft == rightで止まる実装にはなってるんですけど、そこまで読まなくても、left > rightになる場合大丈夫かしらと不安になる必要がなくなるからでしょうか。

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.

安心感というよりは、上から読んでいったときに、left > right の場合がないと確定するのは、sortedArrayToBST の定義が終わった時になりますね。しかも、数学的帰納法を利用して考えることになります。

読む人の「心の理論」
https://discord.com/channels/1084280443945353267/1225849404037009609/1234206158630289450

パズルを解かせる
https://discord.com/channels/1084280443945353267/1200089668901937312/1211248049884499988

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ありがとうございます、納得しました。
以前下の「パズルを解かせる」を読んだのですが、この感覚まだ染み付いていませんでした。。

return None

root = TreeNode()
node_range_pairs = [(root, (0, len(nums)))]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

好みですが、ちょっと同じ行にカッコが多いなと思いました。leftとrightはまとめなくても良いかもです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants