-
Notifications
You must be signed in to change notification settings - Fork 0
617. Merge Two Binary Trees #25
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
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,30 @@ | ||
| /** | ||
| * 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: | ||
| TreeNode* mergeTrees(TreeNode* node1, TreeNode* node2) { | ||
| if (!node1 && !node2) { | ||
| return nullptr; | ||
| } | ||
| if (!node1) { | ||
| return node2; | ||
| } | ||
| if (!node2) { | ||
| return node1; | ||
| } | ||
| node1->val += node2->val; | ||
| node1->left = mergeTrees(node1->left, node2->left); | ||
| node1->right = mergeTrees(node1->right, node2->right); | ||
|
|
||
| return node1; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| ## ステップ1 | ||
| ルール通りすごく愚直にかいた | ||
| 一つ目のnodeを用いて値を足すのか、欠損しているnodeを足すのか判定を行った | ||
|
|
||
| node間がoverlapしている場合つまりどちらもnullptrではに場合は、値の足し算と探索候補としてqueueに追加 | ||
| 2つ目のnodeのみがnullptrでない場合は、1つ目のnodeを上書き | ||
|
|
||
| 上記を2つのnodeの要素(node)がなくなるまでループさせて最終的に一つ目のnodeを返却 | ||
| 30分ほど掛かった | ||
| 時間計算量 | ||
| O(n) | ||
|
|
||
| 空間計算量 | ||
| O(n) | ||
| ## ステップ2 | ||
| ・queueに追加するもしくは片方のnodeにmergeする部分を関数化(MergeOrPushQueue) | ||
| 2種類の作業を1つの関数で行っているのは微妙な気がする | ||
|
|
||
| ・MergeOrPushQueueは外側から使われないのでprivate化 | ||
| TwoNodesはメンバー関数からのみのアクセスを許可するようにprivate化 | ||
|
|
||
| ## 他の解法 | ||
| dfsで解くこともできる | ||
| dfs.cppに実装 | ||
| この場合も | ||
| 時間計算量 | ||
| O(n) | ||
|
|
||
| 空間計算量 | ||
| O(n) | ||
|
|
||
| 新しくnodeを作る方法 | ||
| TreeNodeクラスがデストラクタをどのように定義しているのか気になるところ | ||
|
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. TreeNodeのdtorはtrivialだと思います。
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
とございました。https://en.cppreference.com/w/cpp/language/destructor 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. LeetCodeのTreeNodeでは、dtorが定義されていないので、defaut dtorがコンバイラによって追加されています。
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
|
||
| 左右のノードの処理は似ているので関数化出来そうだけど、可読性が下がりそうなのでやめた | ||
| 左右のどちらを作業しているのかis_leftのような引数を持たせてこれの値によって処理分けを想定 | ||
|
|
||
| ## Discord他のPRなど | ||
| 新しくnodeを作る方法もある何を持って選択肢たか意識する | ||
| >新しいのを作るか作らないのか、古い入力を壊すのか壊さないのか、共有するのかしないのか(変更しない前提ならばメモリー使用量が減る)、などのオプションがあって、自分がどれを「選択」したかを意識しましょう。 | ||
| https://github.com/fhiyo/leetcode/pull/25 | ||
| 新しく作るという手段は思いついたけど、入力と分けて管理する必要性や新しくnodeを管理するコストを考えて | ||
| 片方に追加していく方式にした。 | ||
|
Comment on lines
+41
to
+42
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. @fhiyo ありがとうございます。 入力を破壊している。 |
||
|
|
||
| https://github.com/nittoco/leetcode/pull/30 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| /** | ||
| * 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 { | ||
| private: | ||
|
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. privateはpublicのあとに書いたらいいでしょう。https://google.github.io/styleguide/cppguide.html#Declaration_Order
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 |
||
| struct 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. このstructを作ることで特にわかりやすくなっていないように感じます。
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 元々実装でstructを使うことで親と左右の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. メンバー変数名がイマイチなように感じました。
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 |
||
| TreeNode* new_node; | ||
| TreeNode* first_node; | ||
| TreeNode* second_node; | ||
| }; | ||
|
|
||
| public: | ||
| TreeNode* mergeTrees(TreeNode* node1, TreeNode* node2) { | ||
| if (!node1 && !node2) { | ||
| return nullptr; | ||
| } | ||
| if (!node1) { | ||
| return node2; | ||
| } | ||
| if (!node2) { | ||
| return node1; | ||
| } | ||
|
|
||
| TreeNode* new_root = new TreeNode(node1->val + node2->val); | ||
|
|
||
| queue<Nodes> search_nodes; | ||
| search_nodes.emplace(new_root, node1, node2); | ||
|
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. タプルのようなものを利用して、new_root, node1, node2を1つにまとめて突っ込んだ方がわかりやすいかなと思いました。
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. 今回はstructを使って指摘の三つを一緒に管理するようにしてみました。 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. なるほど、知らなかったですありがとうございます |
||
|
|
||
| while (!search_nodes.empty()) { | ||
| const auto [current_node, first_node, second_node] = std::move(search_nodes.front()); | ||
|
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. struct Nodesの場合、move constructorもcopy constructorも同じ処理になると思います。
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を実装してmoveの動作確認してみます。
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
https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types 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. default move ctorはメンバー変数ごとにmoveが行われます。intやポインタなどbuilt-in型の変数の場合は、単なる代入になります。 |
||
| search_nodes.pop(); | ||
|
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に、nodeがNoneの時も突っ込んじゃって、pop()してから判定する方法もありますね(https://github.com/TORUS0818/leetcode/pull/25/files)
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 |
||
|
|
||
| // 左の子ノードを処理 | ||
| TreeNode* first_left = nullptr; | ||
| TreeNode* second_left = nullptr; | ||
| if (first_node) { | ||
| first_left = first_node->left; | ||
|
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 (second_node) { | ||
| second_left = second_node->left; | ||
| } | ||
| if (first_left || second_left) { | ||
| int left_val = 0; | ||
| if (first_left) { | ||
| left_val += first_left->val; | ||
| } | ||
| if (second_left) { | ||
| left_val += second_left->val; | ||
| } | ||
| current_node->left = new TreeNode(left_val); | ||
| search_nodes.emplace(current_node->left, first_left, second_left); | ||
| } | ||
|
|
||
| // 右の子ノードを処理 | ||
| TreeNode* first_right = nullptr; | ||
| TreeNode* second_right = nullptr; | ||
| if (first_node) { | ||
| first_right = first_node->right; | ||
| } | ||
| if (second_node) { | ||
| second_right = second_node->right; | ||
| } | ||
| if (first_right || second_right) { | ||
| int right_val = 0; | ||
| if (first_right) { | ||
| right_val += first_right->val; | ||
| } | ||
| if (second_right) { | ||
| right_val += second_right->val; | ||
| } | ||
| current_node->right = new TreeNode(right_val); | ||
| search_nodes.emplace(current_node->right, first_right, second_right); | ||
| } | ||
| } | ||
|
|
||
| return new_root; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /** | ||
| * 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: | ||
| TreeNode* mergeTrees(TreeNode* node1, TreeNode* node2) { | ||
| TreeNode* new_root = new TreeNode(); | ||
| queue<Nodes> search_nodes; | ||
| search_nodes.emplace(new_root, node1, node2); | ||
|
|
||
| while (!search_nodes.empty()) { | ||
| auto [current_node, left_child, right_child] = search_nodes.front(); | ||
| search_nodes.pop(); | ||
| if (!left_child && !right_child) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int current_val = 0; | ||
| if (left_child) { | ||
| current_val += left_child->val; | ||
| } | ||
| if (right_child) { | ||
| current_val += right_child->val; | ||
| } | ||
| current_node->val = current_val; | ||
|
|
||
| // 左の子ノードを処理 | ||
| TreeNode* left_first = nullptr; | ||
| if (left_child && left_child->left) { | ||
| left_first = left_child->left; | ||
| } | ||
| TreeNode* left_second = nullptr; | ||
| if (right_child && right_child->left) { | ||
| left_second = right_child->left; | ||
| } | ||
| if (left_first || left_second) { | ||
| current_node->left = new TreeNode(); | ||
| search_nodes.emplace(current_node->left, left_first, left_second); | ||
| } | ||
|
|
||
| // 右の子ノードを処理 | ||
| TreeNode* right_first = nullptr; | ||
| if (left_child && left_child->right) { | ||
| right_first = left_child->right; | ||
| } | ||
| TreeNode* right_second = nullptr; | ||
| if (right_child && right_child->right) { | ||
| right_second = right_child->right; | ||
| } | ||
| if (right_first || right_second) { | ||
| current_node->right = new TreeNode(); | ||
| search_nodes.emplace(current_node->right, right_first, right_second); | ||
| } | ||
| } | ||
|
|
||
| return new_root; | ||
| } | ||
|
|
||
| private: | ||
| struct Nodes { | ||
| TreeNode* node; | ||
| TreeNode* left_child; | ||
| TreeNode* right_child; | ||
| }; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| /** | ||
| * 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: | ||
| TreeNode* mergeTrees(TreeNode* node1, TreeNode* node2) { | ||
| if (!node1 && !node2) { | ||
| return nullptr; | ||
| } | ||
| TreeNode* new_root = new TreeNode(); | ||
| queue<MergedAndOriginalNodes> search_nodes; | ||
| search_nodes.push({new_root, node1, node2}); | ||
|
|
||
| while (!search_nodes.empty()) { | ||
| auto [current_node, first_node, second_node] = search_nodes.front(); | ||
| search_nodes.pop(); | ||
|
|
||
| int current_val = 0; | ||
| if (first_node) { | ||
| current_val += first_node->val; | ||
| } | ||
| if (second_node) { | ||
| current_val += second_node->val; | ||
| } | ||
| current_node->val = current_val; | ||
|
|
||
| // 左の子ノードを処理 | ||
| TreeNode* first_left = nullptr; | ||
| if (first_node) { | ||
| first_left = first_node->left; | ||
| } | ||
| TreeNode* second_left = nullptr; | ||
| if (second_node) { | ||
| second_left = second_node->left; | ||
| } | ||
| if (first_left || second_left) { | ||
| current_node->left = new TreeNode(); | ||
| search_nodes.emplace(current_node->left, first_left, second_left); | ||
| } | ||
|
|
||
| // 右の子ノードを処理 | ||
| TreeNode* first_right = nullptr; | ||
| if (first_node) { | ||
| first_right = first_node->right; | ||
| } | ||
| TreeNode* second_right = nullptr; | ||
| if (second_node) { | ||
| second_right = second_node->right; | ||
| } | ||
| if (first_right || second_right) { | ||
| current_node->right = new TreeNode(); | ||
| search_nodes.push({current_node->right, first_right, second_right}); | ||
| } | ||
| } | ||
|
|
||
| return new_root; | ||
| } | ||
|
|
||
| private: | ||
| struct MergedAndOriginalNodes { | ||
| TreeNode* node; | ||
| TreeNode* left_child; | ||
| TreeNode* right_child; | ||
| }; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /** | ||
| * 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: | ||
| struct TwoNodes { | ||
| TreeNode* first_node; | ||
| TreeNode* second_node; | ||
| }; | ||
|
|
||
| TreeNode* mergeTrees(TreeNode* node1, TreeNode* node2) { | ||
| if (!node1 && !node2) { | ||
| return nullptr; | ||
| } | ||
| if (!node1) { | ||
| return node2; | ||
| } | ||
| if (!node2) { | ||
| return node1; | ||
| } | ||
|
|
||
| queue<TwoNodes> search_nodes; | ||
| search_nodes.emplace(node1, node2); | ||
| while (!search_nodes.empty()) { | ||
| auto [first_node, second_node] = std::move(search_nodes.front()); | ||
| search_nodes.pop(); | ||
|
|
||
| first_node->val += second_node->val; | ||
|
|
||
| if (first_node->left && second_node->left) { | ||
| search_nodes.emplace(first_node->left, second_node->left); | ||
| } else if (second_node->left) { | ||
| first_node->left = second_node->left; | ||
| } | ||
|
|
||
| if (first_node->right && second_node->right) { | ||
| search_nodes.emplace(first_node->right, second_node->right); | ||
| } else if (second_node->right) { | ||
| first_node->right = second_node->right; | ||
| } | ||
| } | ||
|
|
||
| return node1; | ||
| } | ||
| }; |
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.
まず再帰で書いてみるのが自然な気がします。