-
Notifications
You must be signed in to change notification settings - Fork 0
102. Binary Tree Level Order 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?
Changes from all commits
69adafc
319a303
97045e7
2eeaea0
250448d
abff5d6
9ffc2a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| if (!root) { | ||
| return {}; | ||
| } | ||
|
|
||
| vector<vector<int>> level_to_values; | ||
| ConstructLevelOrder(root, level_to_values, 0); | ||
| return level_to_values; | ||
| } | ||
|
|
||
| private: | ||
| void ConstructLevelOrder(const TreeNode* node , vector<vector<int>>& level_to_values, int level) { | ||
| if (!node) { | ||
| return; | ||
| } | ||
| if (level >= level_to_values.size()) { | ||
| level_to_values.push_back({}); | ||
| } | ||
| level_to_values[level].push_back(node->val); | ||
| ConstructLevelOrder(node->left, level_to_values, level + 1); | ||
| ConstructLevelOrder(node->right, level_to_values, level + 1); | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values; | ||
| ConstructLevelOrder(root, level_to_values, 0); | ||
| return level_to_values; | ||
| } | ||
|
|
||
| private: | ||
| void ConstructLevelOrder(const TreeNode* node , vector<vector<int>>& level_to_values, int level) { | ||
| if (!node) { | ||
| return; | ||
| } | ||
| if (level >= level_to_values.size()) { | ||
| level_to_values.push_back({}); | ||
| } | ||
| level_to_values[level].push_back(node->val); | ||
| ConstructLevelOrder(node->left, level_to_values, level + 1); | ||
| ConstructLevelOrder(node->right, level_to_values, level + 1); | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ## ステップ1 | ||
| 深さと値をセットで保存しておけば解けそう | ||
|
|
||
| level_to_values[depth].emplace_back(node->val);の部分を | ||
| 返却用のvector<vector<int>>で行いたかったが | ||
| vectorに対してサイズ確定前のインデックスにアクセスするとエラーとなる | ||
| なのでmapを挟む形にした。15分ほど | ||
|
|
||
| 時間計算量 | ||
| O(n log n) | ||
| 空間計算量 | ||
| O(n) | ||
|
|
||
| ## ステップ2 | ||
| ・queueに入れてから、nodeが有効なのか判断する方に変更 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. あくまで個人的ですが、自分はqueueに入れる前に判断する方が好きです。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 確かにこれまでの類似問題と比較しても、if (!values.empty()) { ... }は特別に処理を入れてますね。 |
||
| 短くかける | ||
| 下記を参考に変更 | ||
| https://github.com/shining-ai/leetcode/pull/26/commits/c90e9ee927b79c6002701924828b3eefcb3281bc | ||
|
|
||
| ・データの持ち方変更 | ||
| whileループの中でさらにループを作りvectorを作りその中に同じ階層のvalueを突っ込んで | ||
| 内側のループ後にvector<vector<int>>に突っ込めばmapに変形する必要がなくなる | ||
| 登場人物が減るので読み易い | ||
| また、階層情報と値を対でもつつようがなくなる | ||
|
|
||
| queueのサイズをforループの宣言内で定義していてハマった。 | ||
| ループ内でqueueに突っ込んでいくので想定外の動きとなる | ||
|
|
||
| ・変数名変更 | ||
| vector<vector<int>>を格納する変数をvaluesからlevel_to_values | ||
| 値(たち)に対する階層 | ||
|
|
||
| ## 他の解法 | ||
| dfs(再帰)でも解いてみる | ||
| 下記を参考 | ||
| https://leetcode.com/problems/binary-tree-level-order-traversal/solutions/3196962/c-bfs-dfs-o-n-explained/ | ||
|
|
||
| 関数化しないで描こうとしたが、BFSとあまり変わらない感じになったのでやめた | ||
| queueを使った方が再帰より処理が追い易いと感じる | ||
| 時間計算量 | ||
| O(n) | ||
| 空間計算量 | ||
| O(n) | ||
|
|
||
| ## 先延ばしにしていたstd::moveとcopy周りについて調べる | ||
| ・vectorをスクラッチで定義 | ||
| 49. Group Anagramsでアドバイス頂いている | ||
| >練習として、簡単なstd::vectorのようなクラスを自分で作成して、copy/move constructor/assignmentを定義してみたらいいかと思います。 | ||
| https://github.com/Ryotaro25/leetcode_first60/pull/13 | ||
|
|
||
| ・kazukiiiさんの解説 | ||
| https://github.com/Ryotaro25/leetcode_first60/pull/13#discussion_r1664897652 | ||
| ・右辺値参照・ムーブセマンティクス | ||
| https://cpprefjp.github.io//lang/cpp11/rvalue_ref_and_move_semantics.html | ||
| ・C++ のムーブを理解する | ||
| https://zenn.dev/mafafa/articles/cba24383d46900 | ||
| ・How to implement our own Vector Class in C++? | ||
| https://www.geeksforgeeks.org/how-to-implement-our-own-vector-class-in-c/ | ||
|
|
||
| **メモ(ポイントなど)** | ||
| *束縛とは?* | ||
| 下記の例のように、&や&&をつけることで右辺値でのみor左辺値でのみアクセスできるように設定すること | ||
| 左辺値参照 | ||
| int& lvalue_ref_1 = x; // OK | ||
| int& lvalue_ref_2 = 0; // Error 右辺値を左辺値参照で束縛している | ||
| 右辺値参照 | ||
| int&& rvalue_ref_1 = x; // Error 左辺値を右辺値参照で束縛している | ||
| int&& rvalue_ref_2 = 0; // OK | ||
|
|
||
| *ムーブされた変数は右辺値となり、それ以降使える保証はなくなる* | ||
| 変数がさし示している値を付け替えるイメージだったが | ||
| ex) | ||
| std::string x = "Hello, world!"; | ||
| std::string y = std::move(x); | ||
| 実際はmoveを通してxを右辺値に変換して、代入が行われる | ||
| 上記の後、xを無効化する(これはクラスによる) | ||
|
|
||
| コピーとの違いは、左辺値で受け取るのか右辺値で受け取れるのかの違い | ||
| また、moveの場合は元のオブジェクトを無効化する | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| if (!root) { | ||
| return {}; | ||
| } | ||
| map<int, vector<int>> level_to_values; | ||
|
|
||
| queue<NodeAndDepth> node_and_depth; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 細かいですが複数形にすると良さそうです。 |
||
| node_and_depth.emplace(root, 0); | ||
| while (!node_and_depth.empty()) { | ||
| auto [node, depth] = node_and_depth.front(); | ||
| node_and_depth.pop(); | ||
|
|
||
| level_to_values[depth].emplace_back(node->val); | ||
| if (node->left) { | ||
| node_and_depth.emplace(node->left, depth + 1); | ||
| } | ||
| if (node->right) { | ||
| node_and_depth.emplace(node->right, depth + 1); | ||
| } | ||
| } | ||
|
|
||
| vector<vector<int>> values; | ||
| for (const auto& [depth, vals] : level_to_values) { | ||
| values.emplace_back(vals); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. コピーが走っていそうです。またこの場合その場でオブジェクトを構築している訳ではないので、push_backでも同じ動きになると思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kazukiii こちらに処理を追加したファイルを上げました(step5.cpp)。 |
||
| } | ||
|
|
||
| return values; | ||
| } | ||
|
|
||
| private: | ||
| struct NodeAndDepth { | ||
| TreeNode* node; | ||
| int depth; | ||
| }; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values = {}; | ||
|
|
||
| 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. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 英字句にすると number of nodes になると思うので、num_nodesの方が良さそうです。 |
||
| vector<int> values = {}; | ||
| for (int i = 0; i < nodes_num; i++) { | ||
| auto node = same_level_nodes.front(); | ||
| same_level_nodes.pop(); | ||
|
|
||
| if (!node) { | ||
| continue; | ||
| } | ||
| values.emplace_back(node->val); | ||
| same_level_nodes.emplace(node->left); | ||
| same_level_nodes.emplace(node->right); | ||
| } | ||
|
|
||
| if (!values.empty()) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. キューに nullptr も入れていることによってこの辺りが逆に複雑になっているような気がします。 |
||
| level_to_values.emplace_back(values); | ||
| } | ||
| } | ||
|
|
||
| return level_to_values; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values = {}; | ||
|
|
||
| queue<TreeNode*> same_level_nodes; | ||
| same_level_nodes.emplace(root); | ||
| 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. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Yoshiki-Iwasa There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一般に、一つの変数に二つの役割を持たすのはいまいちな気がします(自分もよくやってしまいますが、、、)
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nittoco |
||
| auto node = same_level_nodes.front(); | ||
| same_level_nodes.pop(); | ||
|
|
||
| if (!node) { | ||
| continue; | ||
| } | ||
| values.emplace_back(node->val); | ||
| same_level_nodes.emplace(node->left); | ||
| same_level_nodes.emplace(node->right); | ||
| } | ||
|
|
||
| if (!values.empty()) { | ||
| level_to_values.emplace_back(values); | ||
| } | ||
| } | ||
|
|
||
| return level_to_values; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values = {}; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @liquo-rice |
||
| if (!root) { | ||
| return level_to_values; | ||
| } | ||
|
|
||
| vector<TreeNode*> current_level_nodes = {root}; | ||
| while (!current_level_nodes.empty()) { | ||
| vector<int> values = {}; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. C++では参照を受け取ってそこへ直接書き込むことも出来ますね。ご参考までに。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます! |
||
| vector<TreeNode*> next_level_nodes = {}; | ||
|
|
||
| for (const auto& node : current_level_nodes) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ポインタへの参照にする意味はなさそうです
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 確かにアドレスをさし示しているので意味ないですね。。。失礼しました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. & をつけるかは、サイズや変更したいかなどで決めましょう。 |
||
| values.emplace_back(node->val); | ||
| if (node->left) { | ||
| next_level_nodes.emplace_back(node->left); | ||
| } | ||
| if (node->right) { | ||
| next_level_nodes.emplace_back(node->right); | ||
| } | ||
| } | ||
| level_to_values.emplace_back(values); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. copy constructorが呼ばれそうです |
||
| current_level_nodes = next_level_nodes; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. copy assignmentが呼ばれそうです
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @liquo-rice メモにポイントを纏めてみましたので認識に誤りございましたら指摘頂きたいです🙇
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 返却値がvector<vector>であったため、既存のvectorに置き換えて自分の定義を使うことができませんでした。なのでクラスだけ作りました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. swap を使うのも一つです。 |
||
| } | ||
|
|
||
| return level_to_values; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| /** | ||
| * Definition for a binary tree node. | ||
| * struct TreeNode { | ||
| * int val; | ||
| * TreeNode *left; | ||
| * TreeNode *right; | ||
| * TreeNode() : val(0), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} | ||
| * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| vector<vector<int>> levelOrder(TreeNode* root) { | ||
| vector<vector<int>> level_to_values = {}; | ||
| if (!root) { | ||
| return level_to_values; | ||
| } | ||
|
|
||
| vector<TreeNode*> current_level_nodes = {root}; | ||
| while (!current_level_nodes.empty()) { | ||
| vector<int> values = {}; | ||
| vector<TreeNode*> next_level_nodes = {}; | ||
|
|
||
| for (const auto node : current_level_nodes) { | ||
| values.emplace_back(node->val); | ||
| if (node->left) { | ||
| next_level_nodes.emplace_back(node->left); | ||
| } | ||
| if (node->right) { | ||
| next_level_nodes.emplace_back(node->right); | ||
| } | ||
| } | ||
| level_to_values.emplace_back(std::move(values)); | ||
| current_level_nodes = std::move(next_level_nodes); | ||
| } | ||
|
|
||
| return level_to_values; | ||
| } | ||
| }; |
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.
これ不要かなと思います
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.
@fhiyo
ご指摘のとおり不要でした。修正しました。