Skip to content

102. Binary Tree Level Order Traversal#28

Open
Ryotaro25 wants to merge 7 commits intomainfrom
problem26
Open

102. Binary Tree Level Order Traversal#28
Ryotaro25 wants to merge 7 commits intomainfrom
problem26

Conversation

@Ryotaro25
Copy link
Copy Markdown
Owner

問題へのリンク
https://leetcode.com/problems/binary-tree-level-order-traversal/description/
問題文(プレミアムの場合)

備考

次に解く問題の予告
Binary Tree Zigzag Level Order Traversal

フォルダ構成
LeetCodeの問題ごとにフォルダを作成します。
フォルダ内は、step1.cpp、step2.cpp、step3.cpp、dfs.cppとmemo.mdとなります。

memo.md内に各ステップで感じたことを追記します。

vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> level_to_values = {};

queue<TreeNode*> smae_level_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.

smaeとは何でしょうか?typoかと思ったんですがstep2でもあったので

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.

@fhiyo
レビューありがとうございます。
サジェスト(補完)を使っていたので気づかないまま流用しておりました。
失礼しました。

Comment on lines +15 to +17
if (!root) {
return {};
}
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
Owner Author

Choose a reason for hiding this comment

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

@fhiyo
ご指摘のとおり不要でした。修正しました。

O(n)

## ステップ2
・queueに入れてから、nodeが有効なのか判断する方に変更
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

あくまで個人的ですが、自分はqueueに入れる前に判断する方が好きです。
ゴミかもしれないけどとりあえずqueueに入れて後で調整する、という方法だとちょっと認知負荷がある気がしたので...今回だと if (!values.empty()) { ... } の条件文を自分だと忘れそうだなと思いました

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.

確かにこれまでの類似問題と比較しても、if (!values.empty()) { ... }は特別に処理を入れてますね。
yoshikiさんからのレビュー内容も踏まえて、queue管理をvectorに変更しvectorに入れる前に判断する方式に変更しました。ありがとうございます。

while (!same_level_nodes.empty()) {
int nodes_num = same_level_nodes.size();
vector<int> values = {};
for (int i = 0; i < nodes_num; i++) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

same_level_nodesって命名微妙かなと思います
このループのなかで次のレベルのノードも入ってるので

same_level_nodesは単純なqueueにしちゃってsame_level_nodes,next_level_nodesそれぞれの配列を逐一用意してあげたほうが読みやすくなるのではと思いました

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.

@Yoshiki-Iwasa
レビューありがとうございます。
現在と次の2種のnodeが入っているので変数名正しく無いですね。それぞれを別管理にする方式に変更してみました。
step4.cppとなります。

97045e7

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
Owner Author

Choose a reason for hiding this comment

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

@nittoco
レビューありがとうございます。
これは意識して気をつけようと思います🙇

}
}
level_to_values.emplace_back(values);
current_level_nodes = next_level_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.

copy assignmentが呼ばれそうです

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.

@liquo-rice
レビューありがとうございます。こちらに処理を追加したファイルを上げました(step5.cpp)。
copy/move周りを理解するために、前に教えていただいたvectorを自前で作ってcopy/moveにconstructor/assignmentを実装してみました(vector.cpp)。

メモにポイントを纏めてみましたので認識に誤りございましたら指摘頂きたいです🙇
先延ばしにしておりましたがよろしくお願いいたします。
2eeaea0

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.

返却値がvector<vector>であったため、既存のvectorに置き換えて自分の定義を使うことができませんでした。なのでクラスだけ作りました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

swap を使うのも一つです。

next_level_nodes.emplace_back(node->right);
}
}
level_to_values.emplace_back(values);
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 constructorが呼ばれそうです

vector<int> values = {};
vector<TreeNode*> next_level_nodes = {};

for (const auto& node : current_level_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.

ポインタへの参照にする意味はなさそうです

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.

& をつけるかは、サイズや変更したいかなどで決めましょう。

class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> level_to_values = {};
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
Owner Author

Choose a reason for hiding this comment

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

@liquo-rice
effective c++の4項を読んで自分でデフォルトの動きを覚えるより、オブジェクトは初期化を必ず行う方が今の自分にはいいと思いました。
「vectorはいつでも初期化されると保証されている」とは記載ございました。

}
map<int, vector<int>> level_to_values;

queue<NodeAndDepth> node_and_depth;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

細かいですが複数形にすると良さそうです。node_and_depths


vector<vector<int>> values;
for (const auto& [depth, vals] : level_to_values) {
values.emplace_back(vals);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コピーが走っていそうです。またこの場合その場でオブジェクトを構築している訳ではないので、push_backでも同じ動きになると思います。

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.

@kazukiii
レビューありがとうございます。
左辺値と右辺値で挙動が変わるのは理解しておりませんでした。ありがとうございます。
https://en.cppreference.com/w/cpp/container/vector/push_back

こちらに処理を追加したファイルを上げました(step5.cpp)。
この辺りを理解するために、前に教えていただいたvectorを自前で作ってcopy/moveにconstructor/assignmentを実装してみました(vector.cpp)。また以前いただいた資料も再度読みました。
2eeaea0

queue<TreeNode*> same_level_nodes;
same_level_nodes.emplace(root);
while (!same_level_nodes.empty()) {
int nodes_num = same_level_nodes.size();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

英字句にすると number of nodes になると思うので、num_nodesの方が良さそうです。

same_level_nodes.emplace(node->right);
}

if (!values.empty()) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

キューに nullptr も入れていることによってこの辺りが逆に複雑になっているような気がします。


vector<TreeNode*> current_level_nodes = {root};
while (!current_level_nodes.empty()) {
vector<int> values = {};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

C++では参照を受け取ってそこへ直接書き込むことも出来ますね。ご参考までに。
vector<int>& values = level_to_values.emplace_back();

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.

ありがとうございます!

@nittoco
Copy link
Copy Markdown

nittoco commented Aug 24, 2024

見ました!
moveと右辺値参照のところ勉強になりました🙏

}

// move コンストラクター
MyVector(MyVector&& r) : arr(new T[r.capacity]), capacity(r.capacity), current(r.current) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

move ctorとinsertの実装に問題がありそうです。見直してみてください。

Copy link
Copy Markdown
Owner Author

@Ryotaro25 Ryotaro25 Aug 25, 2024

Choose a reason for hiding this comment

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

@liquo-rice
ご確認頂きありがとうございます。
再度自分のコードを読み直しました。

move ctor
moveであるのみnewであったりコピーをしていることが問題だと思いました。
なので初期化子演算子内でnewを使わないようにして、forループの部分は削除しました。

insert
インデックスがマイナスなど、不正なインデックスに対してハンドリングがなかったです。
インデックスが0より下もしくはキャパ以上の場合は例外を投げるようにしました。

250448d

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

最後の後ろに追加する場合以外は、単なる代入になっているようです。
https://en.cppreference.com/w/cpp/container/vector/insert

Copy link
Copy Markdown
Owner Author

@Ryotaro25 Ryotaro25 Aug 28, 2024

Choose a reason for hiding this comment

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

@liquo-rice

If after the operation the new size() is greater than old capacity() a reallocation takes place

現在のサイズを超える場合は、動的にサイズを変更させる必要ございましだ🙇
push_back内に定義していたサイズ変更処理を外出ししてresize()関数を作りました。

Linear in count plus linear in the distance between pos and end of the container.

途中に挿入された場合、シフトする必要ございました。
こちらが修正したものになります。
abff5d6

vector<TreeNode*> next_level_nodes = {};

for (const auto node : current_level_nodes) {
values.emplace_back(std::move(node->val));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

node->valの型はintなので、moveは不要です。

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.

@liquo-rice
失礼しました。左辺値と右辺値の取り扱いに慣れるまでは、ドキュメントを確認しながら進めるようにします🙇

@TORUS0818
Copy link
Copy Markdown

拝見しました。
コメント以外の部分は良いと思いました。

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.

8 participants