-
Notifications
You must be signed in to change notification settings - Fork 0
105. Construct Binary Tree from Preorder and Inorder Traversal #28
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
base: main
Are you sure you want to change the base?
105. Construct Binary Tree from Preorder and Inorder Traversal #28
Conversation
| - inorderの中から目当てのものが見つかるまで | ||
| slices.Indexを呼ぶので、buildTree一回の計算量はO(n^2)。 | ||
| buildTreeは再帰的にn回呼び出されるのでO(n^3)。 | ||
| - 空間計算量: O(log n)。最悪でO(n) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ビッグオー記法はもともと最悪計算量を表していると考えられるため、空間計算量 O(n) としてよいと思います。
| slices.Indexを呼ぶので、buildTree一回の計算量はO(n^2)。 | ||
| buildTreeは再帰的にn回呼び出されるのでO(n^3)。 | ||
| - 空間計算量: O(log n)。最悪でO(n) | ||
| - 1スタックフレームサイズはO(1)でそれがlog n個、 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
平衡二分木が与えられるとは来ていないため、高さが log n 個と考えるのはまずいと思います。
| - 再帰の深さ: log n。最悪の場合、木が直線だとn | ||
| - 時間計算量: O(n^2) | ||
| - slices.Index -> O(n), buildTreeがn回呼ばれる | ||
| - 空間計算量: O(nlogn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
スタックフレームは最大で n 個積まれるため、 O(n^2) ではないでしょうか?
また、スライスのインデックスを関数の引数として渡すことによって、スライスがコピーされることを避け、空間計算量を削減することはできますか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
遅くなりましたが、スライスのインデックスを関数の引数として渡す方法を2bで書いてみました
Goのスライスは参照渡しなのでスライスの一部分を関数の引数として渡してもその時点ではコピーが作成されないと思いました
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
自分で書いておいてなのですが、スライスのコピーが作られずずっと元のpreorder, inorderの一部を参照することになるのであれば、再帰の深さO(n)より、空間計算量はO(n)になりますか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go は、はい、Python と違ってスライスがコピーされないんでしたね。
https://go.dev/blog/slices-intro
| - n: 木の要素数 | ||
| - 再帰の深さ: log n。最悪の場合、木が直線だとn | ||
| - 時間計算量: O(n^2) | ||
| - slices.Index -> O(n), buildTreeがn回呼ばれる |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あらかじめ inorder の値とインデックスを map で持たせることで、時間計算量を削減することはできますか?
| } | ||
| ``` | ||
|
|
||
| - どういうユースケースでこのようなコードを書くことになるのか気になった |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これ、わりとユースケース不明ですね。どっちかというと、preorder と inorder の結果だけ転がっていて、元のデータが消滅してしまったので仕方がなく直している感じを受けました。
|
|
||
| return buildTreeHelper(0, 0, len(preorder)) | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
もう少しいろいろな解き方が提示されていた記憶があります。Discord を見てみるといいかと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
もう少し調べて2cと2dを追加しました
| leftNodeCount := rootIndexInorder | ||
| rightNodeCount := len(inorder) - leftNodeCount - 1 | ||
| root.Left = buildTree(preorder[1:leftNodeCount+1], inorder[:rootIndexInorder]) | ||
| root.Right = buildTree(preorder[len(preorder)-rightNodeCount:], inorder[rootIndexInorder+1:]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goよくわかってないですが、lenが配列全体を舐めるとすると、L104とL106で2回ループすることになりますね。
これくらいはしょうがないのかもしれませんが…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goのlen(slice)は配列全体を舐めないのでO(1)で取得できます。sliceはインスタンス変数みたいな形で先頭要素へのポインタと長さを保持しているからです
| } | ||
| leftNodeCount := rootInorderIndex - inorderStartIndex | ||
| root.Left = buildTreeRecursive(preorderStartIndex+1, inorderStartIndex, leftNodeCount) | ||
| root.Right = buildTreeRecursive(preorderStartIndex+leftNodeCount+1, rootInorderIndex+1, nodeCount-leftNodeCount-1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
細かいですが、L145の再帰関数の第2引数は、rootInorderIndex+1よりinorderStartIndex+leftNodeCount+1とした方が、第1引数との統一感もありわかりやすいと思いました。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
はい、ここはどう表現しようか悩みました。結局コードの短さを取りましたが、おっしゃっていただいた方法の方が意図が伝わると思いました
| return nil | ||
| } | ||
| root := &TreeNode{Val: preorder[0]} | ||
| stack := []*TreeNode{root} // 既に繋がれたノードのうち左の子を持つ可能性のあるものが積まれる |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
「左の子を持つ可能性のあるもの」というより、こういう気持ちでした(stackはまだ決まってないから積んでるみたいなイメージでした)
nittoco/leetcode#37 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほどです!
自分用メモ
「stack に入っているものは、.right がまだ決まっていないもの」
| func push[E any](stack *[]E, elem E) { | ||
| *stack = append(*stack, elem) | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上のコメントと繋がりますが、こういう情報をstackで管理する方法もありますね
https://discord.com/channels/1084280443945353267/1247673286503039020/1300957769477918791
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/