Conversation
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values = {}; | ||
|
|
||
| queue<TreeNode*> smae_level_nodes; |
There was a problem hiding this comment.
@fhiyo
レビューありがとうございます。
サジェスト(補完)を使っていたので気づかないまま流用しておりました。
失礼しました。
| if (!root) { | ||
| return {}; | ||
| } |
| O(n) | ||
|
|
||
| ## ステップ2 | ||
| ・queueに入れてから、nodeが有効なのか判断する方に変更 |
There was a problem hiding this comment.
あくまで個人的ですが、自分はqueueに入れる前に判断する方が好きです。
ゴミかもしれないけどとりあえずqueueに入れて後で調整する、という方法だとちょっと認知負荷がある気がしたので...今回だと if (!values.empty()) { ... } の条件文を自分だと忘れそうだなと思いました
There was a problem hiding this comment.
確かにこれまでの類似問題と比較しても、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++) { |
There was a problem hiding this comment.
same_level_nodesって命名微妙かなと思います
このループのなかで次のレベルのノードも入ってるので
same_level_nodesは単純なqueueにしちゃってsame_level_nodes,next_level_nodesそれぞれの配列を逐一用意してあげたほうが読みやすくなるのではと思いました
There was a problem hiding this comment.
@Yoshiki-Iwasa
レビューありがとうございます。
現在と次の2種のnodeが入っているので変数名正しく無いですね。それぞれを別管理にする方式に変更してみました。
step4.cppとなります。
There was a problem hiding this comment.
一般に、一つの変数に二つの役割を持たすのはいまいちな気がします(自分もよくやってしまいますが、、、)
| } | ||
| } | ||
| level_to_values.emplace_back(values); | ||
| current_level_nodes = next_level_nodes; |
There was a problem hiding this comment.
@liquo-rice
レビューありがとうございます。こちらに処理を追加したファイルを上げました(step5.cpp)。
copy/move周りを理解するために、前に教えていただいたvectorを自前で作ってcopy/moveにconstructor/assignmentを実装してみました(vector.cpp)。
メモにポイントを纏めてみましたので認識に誤りございましたら指摘頂きたいです🙇
先延ばしにしておりましたがよろしくお願いいたします。
2eeaea0
There was a problem hiding this comment.
返却値がvector<vector>であったため、既存のvectorに置き換えて自分の定義を使うことができませんでした。なのでクラスだけ作りました。
| next_level_nodes.emplace_back(node->right); | ||
| } | ||
| } | ||
| level_to_values.emplace_back(values); |
| vector<int> values = {}; | ||
| vector<TreeNode*> next_level_nodes = {}; | ||
|
|
||
| for (const auto& node : current_level_nodes) { |
There was a problem hiding this comment.
確かにアドレスをさし示しているので意味ないですね。。。失礼しました。
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values = {}; |
There was a problem hiding this comment.
@liquo-rice
effective c++の4項を読んで自分でデフォルトの動きを覚えるより、オブジェクトは初期化を必ず行う方が今の自分にはいいと思いました。
「vectorはいつでも初期化されると保証されている」とは記載ございました。
| } | ||
| map<int, vector<int>> level_to_values; | ||
|
|
||
| queue<NodeAndDepth> node_and_depth; |
|
|
||
| vector<vector<int>> values; | ||
| for (const auto& [depth, vals] : level_to_values) { | ||
| values.emplace_back(vals); |
There was a problem hiding this comment.
コピーが走っていそうです。またこの場合その場でオブジェクトを構築している訳ではないので、push_backでも同じ動きになると思います。
There was a problem hiding this comment.
@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(); |
There was a problem hiding this comment.
英字句にすると number of nodes になると思うので、num_nodesの方が良さそうです。
| same_level_nodes.emplace(node->right); | ||
| } | ||
|
|
||
| if (!values.empty()) { |
There was a problem hiding this comment.
キューに nullptr も入れていることによってこの辺りが逆に複雑になっているような気がします。
|
|
||
| vector<TreeNode*> current_level_nodes = {root}; | ||
| while (!current_level_nodes.empty()) { | ||
| vector<int> values = {}; |
There was a problem hiding this comment.
C++では参照を受け取ってそこへ直接書き込むことも出来ますね。ご参考までに。
vector<int>& values = level_to_values.emplace_back();
|
見ました! |
| } | ||
|
|
||
| // move コンストラクター | ||
| MyVector(MyVector&& r) : arr(new T[r.capacity]), capacity(r.capacity), current(r.current) { |
There was a problem hiding this comment.
move ctorとinsertの実装に問題がありそうです。見直してみてください。
There was a problem hiding this comment.
@liquo-rice
ご確認頂きありがとうございます。
再度自分のコードを読み直しました。
move ctor
moveであるのみnewであったりコピーをしていることが問題だと思いました。
なので初期化子演算子内でnewを使わないようにして、forループの部分は削除しました。
insert
インデックスがマイナスなど、不正なインデックスに対してハンドリングがなかったです。
インデックスが0より下もしくはキャパ以上の場合は例外を投げるようにしました。
There was a problem hiding this comment.
最後の後ろに追加する場合以外は、単なる代入になっているようです。
https://en.cppreference.com/w/cpp/container/vector/insert
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
@liquo-rice
失礼しました。左辺値と右辺値の取り扱いに慣れるまでは、ドキュメントを確認しながら進めるようにします🙇
|
拝見しました。 |
問題へのリンク
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内に各ステップで感じたことを追記します。