diff --git a/102.BinaryTreeLevelOrderTraversal/dfs.cpp b/102.BinaryTreeLevelOrderTraversal/dfs.cpp new file mode 100644 index 0000000..d36edee --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/dfs.cpp @@ -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> levelOrder(TreeNode* root) { + if (!root) { + return {}; + } + + vector> level_to_values; + ConstructLevelOrder(root, level_to_values, 0); + return level_to_values; + } + +private: + void ConstructLevelOrder(const TreeNode* node , vector>& 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); + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/dfs_step2.cpp b/102.BinaryTreeLevelOrderTraversal/dfs_step2.cpp new file mode 100644 index 0000000..f8b8617 --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/dfs_step2.cpp @@ -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> levelOrder(TreeNode* root) { + vector> level_to_values; + ConstructLevelOrder(root, level_to_values, 0); + return level_to_values; + } + +private: + void ConstructLevelOrder(const TreeNode* node , vector>& 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); + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/memo.md b/102.BinaryTreeLevelOrderTraversal/memo.md new file mode 100644 index 0000000..262575a --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/memo.md @@ -0,0 +1,79 @@ +## ステップ1 +深さと値をセットで保存しておけば解けそう + +level_to_values[depth].emplace_back(node->val);の部分を +返却用のvector>で行いたかったが +vectorに対してサイズ確定前のインデックスにアクセスするとエラーとなる +なのでmapを挟む形にした。15分ほど + +時間計算量 +O(n log n) +空間計算量 +O(n) + +## ステップ2 +・queueに入れてから、nodeが有効なのか判断する方に変更 + 短くかける + 下記を参考に変更 + https://github.com/shining-ai/leetcode/pull/26/commits/c90e9ee927b79c6002701924828b3eefcb3281bc + +・データの持ち方変更 + whileループの中でさらにループを作りvectorを作りその中に同じ階層のvalueを突っ込んで + 内側のループ後にvector>に突っ込めばmapに変形する必要がなくなる + 登場人物が減るので読み易い + また、階層情報と値を対でもつつようがなくなる + + queueのサイズをforループの宣言内で定義していてハマった。 + ループ内でqueueに突っ込んでいくので想定外の動きとなる + +・変数名変更 + vector>を格納する変数を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の場合は元のオブジェクトを無効化する diff --git a/102.BinaryTreeLevelOrderTraversal/step1.cpp b/102.BinaryTreeLevelOrderTraversal/step1.cpp new file mode 100644 index 0000000..4767bd5 --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/step1.cpp @@ -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> levelOrder(TreeNode* root) { + if (!root) { + return {}; + } + map> level_to_values; + + queue node_and_depth; + 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> values; + for (const auto& [depth, vals] : level_to_values) { + values.emplace_back(vals); + } + + return values; + } + +private: + struct NodeAndDepth { + TreeNode* node; + int depth; + }; +}; diff --git a/102.BinaryTreeLevelOrderTraversal/step2.cpp b/102.BinaryTreeLevelOrderTraversal/step2.cpp new file mode 100644 index 0000000..24e416d --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/step2.cpp @@ -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> levelOrder(TreeNode* root) { + vector> level_to_values = {}; + + queue same_level_nodes; + same_level_nodes.emplace(root); + while (!same_level_nodes.empty()) { + int nodes_num = same_level_nodes.size(); + vector 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()) { + level_to_values.emplace_back(values); + } + } + + return level_to_values; + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/step3.cpp b/102.BinaryTreeLevelOrderTraversal/step3.cpp new file mode 100644 index 0000000..24e416d --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/step3.cpp @@ -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> levelOrder(TreeNode* root) { + vector> level_to_values = {}; + + queue same_level_nodes; + same_level_nodes.emplace(root); + while (!same_level_nodes.empty()) { + int nodes_num = same_level_nodes.size(); + vector 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()) { + level_to_values.emplace_back(values); + } + } + + return level_to_values; + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/step4.cpp b/102.BinaryTreeLevelOrderTraversal/step4.cpp new file mode 100644 index 0000000..1003e26 --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/step4.cpp @@ -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> levelOrder(TreeNode* root) { + vector> level_to_values = {}; + if (!root) { + return level_to_values; + } + + vector current_level_nodes = {root}; + while (!current_level_nodes.empty()) { + vector values = {}; + vector 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(values); + current_level_nodes = next_level_nodes; + } + + return level_to_values; + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/step5.cpp b/102.BinaryTreeLevelOrderTraversal/step5.cpp new file mode 100644 index 0000000..b5fb6c5 --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/step5.cpp @@ -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> levelOrder(TreeNode* root) { + vector> level_to_values = {}; + if (!root) { + return level_to_values; + } + + vector current_level_nodes = {root}; + while (!current_level_nodes.empty()) { + vector values = {}; + vector 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; + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/step6.cpp b/102.BinaryTreeLevelOrderTraversal/step6.cpp new file mode 100644 index 0000000..1aa203f --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/step6.cpp @@ -0,0 +1,44 @@ +/** + * 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> levelOrder(TreeNode* root) { + if (!root) { + return {}; + } + + vector> level_orderd_values; + queue current_level_nodes; + current_level_nodes.push(root); + + while (!current_level_nodes.empty()) { + queue next_level_nodes; + vector same_level_values; + int current_level_size = current_level_nodes.size(); + for (int i = 0; i < current_level_size; i++) { + auto node = current_level_nodes.front(); + current_level_nodes.pop(); + + same_level_values.push_back(node->val); + if (node->left) { + next_level_nodes.push(node->left); + } + if (node->right) { + next_level_nodes.push(node->right); + } + } + current_level_nodes = next_level_nodes; + level_orderd_values.push_back(std::move(same_level_values)); + } + return level_orderd_values; + } +}; diff --git a/102.BinaryTreeLevelOrderTraversal/vector.cpp b/102.BinaryTreeLevelOrderTraversal/vector.cpp new file mode 100644 index 0000000..844959d --- /dev/null +++ b/102.BinaryTreeLevelOrderTraversal/vector.cpp @@ -0,0 +1,149 @@ +/** + * 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) {} + * }; + */ +template class MyVector { +public: + // メンバ初期化子リストで初期化することで、デフォルトコンストラクタ→代入の処理ではなくなる + // effective c++の4項オブジェクトは、使う前に初期化しようを参照 + MyVector() : arr(new T[1]), capacity(1), current(0) {} + + // newとdeleteの形は合わせておく、未定義を避けるため + // effective c++の16項を参照 + ~MyVector() { + delete[] arr; + } + + // copy コンストラクター + MyVector(const MyVector& other) : arr(new T[other.capacity]), capacity(other.capacity), current(other.current) { + for (int i = 0; i < current; i++) { + arr[i] = other.arr[i]; + } + } + + // move コンストラクター + MyVector(MyVector&& r) : arr(r.capacity), capacity(r.capacity), current(r.current) { + // 元の右辺値を無効化 + r.arr = nullptr; + r.capacity = 0; + r.current = 0; + } + + // copy assignment + MyVector& operator=(const MyVector& other) { + if (this != other) { + delete[] arr; + + arr = new T[other.capacity]; + capacity = other.capacity; + current = other.current; + for (int i = 0; i < capacity; i++) { + arr[i] = other.arr[i]; + } + } + return *this; + } + + // move assignment + MyVector& operator=(MyVector&& r) noexcept { + if (this != &r) { + delete[] arr; + + arr = r.arr; + capacity = r.capacity; + current = r.current; + + r.arr = nullptr; + r.capacity = 0; + r.current = 0; + } + return *this; + } + + T& operator[] (int index) { + if (index >= current || index < 0) { + throw std::out_of_range("Index out of range"); + } + return arr[index]; + } + + void insert(T data, int index) { + // arr[-3] などは無効 + if (index < 0 || index >= current) { + throw std::out_of_range("Index out of range"); + } + + if (current >= capacity) { + resize(); + } + + for (int i = current; i > index; --i) { + arr[i] = arr[i - 1]; + } + + arr[index] = data; + current++; + } + + void push_back(T data) { + if (current == capacity) { + resize(); + } + + arr[current] = data; + current++; + } + + void resize() { + T* temp = new T[2 * capacity]; + for (int i = 0; i < capacity; i++) { + temp[i] = arr[i]; + } + + delete[] arr; + capacity *= 2; + arr = temp; + } + +private: + T* arr; + int capacity; + int current; +} + +class Solution { +public: + vector> levelOrder(TreeNode* root) { + vector> level_to_values = {}; + if (!root) { + return level_to_values; + } + + vector current_level_nodes = {root}; + while (!current_level_nodes.empty()) { + vector values = {}; + vector 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(values); + current_level_nodes = next_level_nodes; + } + + return level_to_values; + } +};