Skip to content
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

102. Binary Tree Level Order Traversal #40

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

102. Binary Tree Level Order Traversal #40

wants to merge 1 commit into from

Conversation

colorbox
Copy link
Owner

@colorbox colorbox commented Feb 18, 2025

https://leetcode.com/problems/binary-tree-level-order-traversal/description/

hayashi-ay/leetcode#32
https://discord.com/channels/1084280443945353267/1200089668901937312/1211248049884499988

leetcode_ahayashi
私は、while だと思っていて、上から読んでいくと、

「level が大きくて nodes_ordered_by_level が足りない場合、足りるように拡張します。そして、拡張した場所に書き込みます。」(読んでいくと、あとから、足りないことがあったとしても1段であることが他のところから分かる。)

「level が大きくて nodes_ordered_by_level が足りない場合、1段だけ拡張します。そして、level 番目に書き込みます。(書き込めなかったら IndexError が投げられます。)」(読んでいくと、1段だけしか拡張しなくても、level 番目が準備されているので例外はないことが分かる。)

というふうに読めます。どっちが読み手にとっていいですか。

1段だけしか拡張しなくても例外が投げられることがないことに気がつくパズルを解かせる必要ないですよね。そうすると、下にするならば、コメント1行付けておいて、くらいの感覚です。

shining-ai/leetcode#26
Mike0121/LeetCode#7

Mike0121/LeetCode#7 (comment)

私はそもそもローカル変数に current を付けておけばいい名前になっているというのが相当違和感です。current は多くの場合、context のようなグローバルな設定などに用いられる傾向が強く、今注目しているもの、というつもりだと標準的用法からかなりずれを感じます。変数名は長ければ読みやすい訳ではないんです。previous, next との対比ならばまだしも。

https://source.chromium.org/search?q=%22current%22%20-concurrent%20filepath:.*%5C.cc$&start=101

sakupan102/arai60-practice#27
fhiyo/leetcode#28
Yoshiki-Iwasa/Arai60#30
kazukiii/leetcode#27
TORUS0818/leetcode#28
nittoco/leetcode#32
Ryotaro25/leetcode_first60#28
goto-untrapped/Arai60#50
hroc135/leetcode#25
olsen-blue/Arai60#26

102/step1.cpp Outdated
Solve Time: 21:38

Time : O(N)
Space : O(N)
Copy link

Choose a reason for hiding this comment

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

これ、再帰でコピーしているので、時間計算量空間計算量もっと大きいように思います。
left で一直線に繋がった場合を考えてみてください。

Copy link
Owner Author

Choose a reason for hiding this comment

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

コメントありがとうございます。
insertのコピーを考慮できていなかったです


private:
vector<vector<int>> merge_two_trees(vector<vector<int>>& left, vector<vector<int>>& right) {
vector<vector<int>> merged_levels;
Copy link

Choose a reason for hiding this comment

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

自分ならこのタイミングで max(left.size(), right.size()) 要素で初期化し、 current_level_vals を経由せずに直接 insert すると思います。 current_level_vals の push_back() にかかるコピーを省けますので。

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど、コメントありがとうございます。
push_backでコピー発生は考慮できていなかったです・・・。

102/step2.cpp Outdated
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> level_order;
queue<TreeNode*> current_level_nodes;
queue<TreeNode*> next_level_nodes;
Copy link

Choose a reason for hiding this comment

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

next_level_nodes の内容をループの次の周回に伝搬する必要がないと思います。スコープを狭めるため、ループの中で定義したほうがよいと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

コメントありがとうございます。
currentとの対比のためのここで宣言していましたが、無駄にスコープが広くなってしまっていました。

102/step2.cpp Outdated
queue<TreeNode*> current_level_nodes;
queue<TreeNode*> next_level_nodes;
current_level_nodes.push(root);
while (true) {
Copy link

Choose a reason for hiding this comment

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

ループの終了条件を先に明示したほうがコードの意図が伝わりやすいように思います。自分なら !current_level_nodes.empty() を条件とすると思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

コメントありがとうございます。
同じ条件が連続するので、若干違和感を感じましたが、while(true)よりは良さそうですね

102/step2.cpp Outdated
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> level_order;
queue<TreeNode*> current_level_nodes;
Copy link

Choose a reason for hiding this comment

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

pop() しなくても、全体を走査できれば同じ処理ができるので、自分なら vector を使うと思います。 queue でも良いと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど、確かに必ずしもpopは必須ではないですね

102/step2.cpp Outdated
Comment on lines 19 to 31
while (!current_level_nodes.empty()) {
auto node = current_level_nodes.front();
current_level_nodes.pop();
if (!node) {
continue;
}
same_level_vals.push_back(node->val);
next_level_nodes.push(node->left);
next_level_nodes.push(node->right);
}
swap(current_level_nodes, next_level_nodes);
if (same_level_vals.empty()) {
break;
Copy link

@olsen-blue olsen-blue Feb 23, 2025

Choose a reason for hiding this comment

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

nodchipさんのコメントと被るかもですが、ループ終了条件が散らばっているのが気になりました。
(多分、!current_level_nodes.empty() で1箇所に集約できるように思います...)
あと、level_orderはノードの回収方法であって、中に何が入ってるのかは、(読み解けばわかりますが)ぱっと見でわかりづらい気がしました。

Copy link
Owner Author

@colorbox colorbox Feb 23, 2025

Choose a reason for hiding this comment

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

コメントありがとうございます。
変数名は変えた方が読みやすくなりそうですね・・・。

class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> level_ordered_nums;
Copy link

Choose a reason for hiding this comment

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

自分はTreeNodeのメンバ変数valに合わせてlevel_ordered_valsにするかなと思いました

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます、確かに名前付けの一貫性は大事ですね。

while (!current_level_nodes.empty()) {
vector<TreeNode*> next_level_nodes;
vector<int> same_level_nums;
for (int i = 0; i < current_level_nodes.size(); ++i) {
Copy link

Choose a reason for hiding this comment

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

ここをfor (auto node : current_level_nodes)にするとこのブロックがすっきりすると思います

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます、確かにこちらでも良さそうですね

break;
}
level_ordered_nums.push_back(same_level_nums);
swap(current_level_nodes, next_level_nodes);
Copy link

Choose a reason for hiding this comment

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

単にcurrent_level_nodes = next_level_nodesでもいいと思うのですが、swapを選んだ理由があったりしますか?

Copy link
Owner Author

Choose a reason for hiding this comment

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

swapの方が速いのと、読みやすさですね

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.

5 participants