-
Notifications
You must be signed in to change notification settings - Fork 0
105. Construct Binary Tree from Preorder and Inorder Traversal #31
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
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,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: | ||
| TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| for (int i = 0; i < inorder.size(); i++) { | ||
| inorder_value_to_index[inorder[i]] = i; | ||
| } | ||
|
|
||
| return BuildTreeHelper(0, inorder.size(), preorder); | ||
| } | ||
|
|
||
| private: | ||
| int preorder_index = 0; | ||
| unordered_map<int, int> inorder_value_to_index; | ||
|
|
||
| TreeNode* BuildTreeHelper(int left_bound, int right_bound, vector<int>& preorder) { | ||
| if (left_bound >= right_bound) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int value = preorder[preorder_index]; | ||
| TreeNode* node = new TreeNode(value); | ||
|
|
||
| int inorder_index = inorder_value_to_index[value]; | ||
| preorder_index++; | ||
| node->left = BuildTreeHelper(left_bound, inorder_index, preorder); | ||
| node->right = BuildTreeHelper(inorder_index + 1, right_bound, preorder); | ||
| return node; | ||
| } | ||
| }; | ||
| 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: | ||
| TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| for (int i = 0; i < inorder.size(); i++) { | ||
| inorder_value_to_index[inorder[i]] = i; | ||
| } | ||
|
|
||
| int preorder_index = 0; | ||
| return BuildTreeHelper(0, inorder.size(), preorder, preorder_index); | ||
| } | ||
|
|
||
| private: | ||
| unordered_map<int, int> inorder_value_to_index; | ||
|
|
||
| TreeNode* BuildTreeHelper(int left_bound, int right_bound, vector<int>& preorder, int& preorder_index) { | ||
| if (left_bound >= right_bound) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int value = preorder[preorder_index]; | ||
| TreeNode* node = new TreeNode(value); | ||
|
|
||
| int inorder_index = inorder_value_to_index[value]; | ||
| preorder_index++; | ||
| node->left = BuildTreeHelper(left_bound, inorder_index, preorder, preorder_index); | ||
| node->right = BuildTreeHelper(inorder_index + 1, right_bound, preorder, preorder_index); | ||
| return node; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| ## ステップ1 | ||
| inorderもしくはpreorderの要素を一方のKeyとして | ||
| インデックスを取得することで何かできないか。。。 | ||
| preorderの最初の3つの要素がrootとその左右になるのか | ||
|
|
||
| 15分考えて分からなかったので、答えを見ないでそれぞれpreorderとinorderはどういったものなのか確認 | ||
| preorder traversal | ||
| https://www.geeksforgeeks.org/preorder-traversal-of-binary-tree/ | ||
| inorder traversal | ||
| https://www.geeksforgeeks.org/inorder-traversal-of-binary-tree/ | ||
|
|
||
| ここで再挑戦 | ||
| 15分考えて分からなかったので回答確認 | ||
| https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solutions/5632202/video-2-solutions-with-o-n-2-and-o-n-time/ | ||
| preorderの要素からinorderのindexを取得して、そのindexの左側が左のnodeに右側が右のnodeに紐づく | ||
| これはinorderが常に左側を優先してトラバースするため | ||
|
|
||
| 時間計算量 | ||
| O(n^2) | ||
| eraseとindexを探すforループの部分でそれぞれO(n) | ||
| 上記を要素の数だけ再帰的にn回呼び出すため | ||
|
|
||
| 空間計算量 | ||
| O(n^2) | ||
| 左右それぞれのvectorを呼び出す部分がO(n) | ||
| 上記を要素の数だけ再帰的にn回呼び出すため | ||
|
|
||
| ## ステップ2 | ||
| ・イテレーターの定義方法変更 | ||
| forループでindexを見つけてからiteratorに変換していたがfind関数が存在していた | ||
|
|
||
|
|
||
| ## 他の解法 | ||
|
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. preorderとinorderを使って順に木を構築する方法もあります。 |
||
| hash_mapを用いた解法もある | ||
| https://github.com/Mike0121/LeetCode/pull/12/commits/d4ccd11c98bbb8982422a7588dee7fddcb062ff7?short_path=37c38ad#diff-37c38adee77a00d4840ea0049203ac45f60966aa4ad1c8b6d80b1dc78d6def37 | ||
| step2に似ているが、vectorを再帰的に呼び出すのではなく | ||
| index(int)をを渡して再帰を行うので処理が軽い | ||
|
|
||
| hash_mapでなくともmapでも可能 | ||
|
|
||
| ## Discordや他のPRなど | ||
| ・自分の解法と違ってpreorder側も新たに作成している | ||
| 自分のは破壊的変更を行なっているので元のpreorderは使えない | ||
| preorder側をindex渡して管理 | ||
| step4.cppに実装 | ||
| https://github.com/TORUS0818/leetcode/pull/31/commits/24492ff4388f596583de9dbf504f7a010a554fc7 | ||
| https://github.com/kazukiii/leetcode/pull/30#discussion_r1685735022 | ||
| https://github.com/Yoshiki-Iwasa/Arai60/pull/33 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * 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* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| if (!inorder.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. if (inorder.empty()) {
return nullptr;
}
...の形の方がコードを読みながら考えることが減って読みやすいかなと思います
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 改めてみてみると最下部にreturn nullptrがあるのは読みづらいですね。 |
||
| int value = preorder[0]; | ||
| preorder.erase(preorder.begin()); | ||
|
|
||
| TreeNode* node = new TreeNode(value); | ||
|
|
||
| int index; | ||
| for (int i = 0; i < inorder.size(); i++) { | ||
| if (inorder[i] == value) { | ||
| index = i; | ||
| } | ||
| } | ||
| vector<int>::iterator position = inorder.begin() + index; | ||
| vector<int> left_inorder(inorder.begin(), position); | ||
| vector<int> right_inorder(position + 1, inorder.end()); | ||
|
|
||
| node->left = buildTree(preorder, left_inorder); | ||
| node->right = buildTree(preorder, right_inorder); | ||
|
|
||
| return node; | ||
| } | ||
| return nullptr; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /** | ||
| * 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* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| if (!inorder.empty()) { | ||
| int value = preorder[0]; | ||
| preorder.erase(preorder.begin()); | ||
|
|
||
| TreeNode* node = new TreeNode(value); | ||
| auto position = find(inorder.begin(), inorder.end(), value); | ||
| vector<int> left_inorder(inorder.begin(), position); | ||
| vector<int> right_inorder(position + 1, inorder.end()); | ||
|
|
||
| node->left = buildTree(preorder, left_inorder); | ||
| node->right = buildTree(preorder, right_inorder); | ||
|
|
||
| return node; | ||
| } | ||
| return nullptr; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /** | ||
| * 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* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| if (!inorder.empty()) { | ||
| int value = preorder[0]; | ||
| preorder.erase(preorder.begin()); | ||
|
|
||
| TreeNode* node = new TreeNode(value); | ||
| auto position = find(inorder.begin(), inorder.end(), value); | ||
| vector<int> left_inorder(inorder.begin(), position); | ||
| vector<int> right_inorder(position + 1, inorder.end()); | ||
|
|
||
| node->left = buildTree(preorder, left_inorder); | ||
| node->right = buildTree(preorder, right_inorder); | ||
|
|
||
| return node; | ||
| } | ||
| return nullptr; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| /** | ||
| * 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* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| return BuildTreeHelper(preorder, 0, preorder.size(), inorder, 0, | ||
| inorder.size()); | ||
| } | ||
|
|
||
| private: | ||
| TreeNode* BuildTreeHelper(const vector<int>& preorder, int preorder_start, int preorder_end, | ||
| const vector<int>& inorder, int inorder_start, int inorder_end) { | ||
|
Comment on lines
+20
to
+21
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. レビューありがとうございます。 |
||
| if (preorder_start >= preorder_end || inorder_start >= inorder_end) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int value = preorder[preorder_start]; | ||
| TreeNode* node = new TreeNode(value); | ||
|
|
||
| int position = FindSeparatingPosition(inorder, inorder_start, inorder_end, value); | ||
|
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.
あと、indexをいじるのは認知不可が上がるので、inorder, preorderそれぞれのsliceを引き回すようにすると読みやすくなると思いました
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
今回複数パターン書いてみましたが、indexを触るverは理解するのが辛かったです。 |
||
|
|
||
| int left_tree_size = position - inorder_start + 1; | ||
| node->left = BuildTreeHelper(preorder, preorder_start + 1, preorder_start + left_tree_size, | ||
| inorder, inorder_start, position); | ||
| node->right = BuildTreeHelper(preorder, preorder_start + left_tree_size, preorder_end, | ||
| inorder, position + 1, inorder_end); | ||
| return node; | ||
| } | ||
|
|
||
| int FindSeparatingPosition(const vector<int>& inorder, int start, int end, int value) { | ||
| for (int i = start; i < end; ++i) { | ||
| if (inorder[i] == value) { | ||
| return i; | ||
| } | ||
| } | ||
| return -1; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /** | ||
| * 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* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| if (inorder.empty()) { | ||
| return nullptr; | ||
| } | ||
| int value = preorder[0]; | ||
| preorder.erase(preorder.begin()); | ||
|
|
||
| TreeNode* node = new TreeNode(value); | ||
| auto position = find(inorder.begin(), inorder.end(), value); | ||
| vector<int> left_inorder(inorder.begin(), position); | ||
| vector<int> right_inorder(position + 1, inorder.end()); | ||
|
|
||
| node->left = buildTree(preorder, left_inorder); | ||
| node->right = buildTree(preorder, right_inorder); | ||
|
|
||
| return node; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| /** | ||
| * 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* buildTree(vector<int>& preorder, vector<int>& inorder) { | ||
| return BuildTreeHelper(preorder, 0, inorder, 0, inorder.size()); | ||
| } | ||
|
|
||
| private: | ||
| TreeNode* BuildTreeHelper(const vector<int>& preorder, int preorder_start, | ||
| const vector<int>& inorder, int inorder_start, int tree_size) { | ||
| if (tree_size <= 0) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int value = preorder[preorder_start]; | ||
| TreeNode* node = new TreeNode(value); | ||
|
|
||
| int inorder_root_index = FindSeparatingIndex(inorder, inorder_start, inorder_start + tree_size, value); | ||
| int left_tree_size = inorder_root_index - inorder_start; | ||
|
|
||
| node->left = BuildTreeHelper(preorder, preorder_start + 1, | ||
| inorder, inorder_start, left_tree_size); | ||
|
|
||
| node->right = BuildTreeHelper(preorder, preorder_start + 1 + left_tree_size, | ||
| inorder, inorder_root_index + 1, tree_size - left_tree_size - 1); | ||
| return node; | ||
| } | ||
|
|
||
| int FindSeparatingIndex(const vector<int>& inorder, int start, int end, int value) { | ||
| for (int i = start; i < end; ++i) { | ||
| if (inorder[i] == value) { | ||
| return i; | ||
| } | ||
| } | ||
| return -1; | ||
| } | ||
| }; |
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.
Solutionインスタンスが作られ、そのインスタンスでbuildTree()が複数回呼ばれた場合を考えるとpreorder_indexが初期化されずバグる気がします。そこを考慮するかという問題はあるかもしれないですが。
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.
たとえば、HTML Parser だったら、HTML 一つにつきインスタンス一つという設計も自然でしょう。呼ぶ側の気持ちになってどう実装するかを考えるということかと思います。
通常、プログラムというのは、誰かに使って欲しいと思って書かれていて、つまり、それがエンジニアリングをしているということです。ライブラリーの場合は、それは呼ぶ相手のためにエンジニアリングをしているはずです。