-
Notifications
You must be signed in to change notification settings - Fork 0
105. Construct Binary Tree from Preorder and Inorder Traversal #30
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,42 @@ | ||
| ## 考察 | ||
| - 過去に解いたことあり | ||
| - 方針 | ||
| - 基本的な考え方は、それぞれのtraversalをrootと左部分木と右部分木に分けること | ||
| - まず、preorderの先頭がroot | ||
| - inorderの中からrootを検索して、その左が左部分木、右が右部分木 | ||
| - 各部分木のサイズもわかる | ||
| - `preorder and inorder consist of unique values.` | ||
| - この制約がかなり重要 | ||
| - あとは再帰的に構築できる | ||
| - 再帰の深さについては、最大で3000なため、C++なら問題ない | ||
| - あとは実装 | ||
|
|
||
| ## Step1 | ||
| - std::findのドキュメントを見た | ||
| - https://en.cppreference.com/w/cpp/algorithm/find | ||
| - 計算量はO(n) | ||
| - time: O(n^2), space: O(n^2) | ||
|
|
||
| ## Step2 | ||
| - vectorのコピーが気になるので、indexを介してpreorder, inorderを使い回す書き方に変更した | ||
| - time: O(n^2), space: O(n) | ||
| - `stpe2.cpp` | ||
| - 他の人のPRを検索 | ||
| - https://github.com/fhiyo/leetcode/pull/31 | ||
| - 「preorderとinorderのstart」と「subtreeのsize」だけで十分 -> 引数は1つ減らせる | ||
| - HashMapを使った高速化 | ||
| - preorderの順にノードを見ていき、木の根から順にノードの場所をinorderの位置を見ながら確定していく手法 | ||
| - このやり方も書いておきたい | ||
| - `step2_preorder.cpp` へ追加 | ||
| - time: O(n^2), space: O(n) | ||
| - https://github.com/YukiMichishita/LeetCode/pull/12 | ||
| - https://github.com/sakupan102/arai60-practice/pull/30 | ||
| - 「定数倍高速化」について | ||
| - https://github.com/sakupan102/arai60-practice/pull/30#discussion_r1599277520 | ||
| - std::rotateは first, middle, lastという表記を使っている | ||
| - https://github.com/sakupan102/arai60-practice/pull/30#discussion_r1599283671 | ||
|
|
||
| ## Step3 | ||
| - 1回目: 11m30s | ||
| - 2回目: 9m13s | ||
| - 3回目: 8m48s |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| /** | ||
| * 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 (preorder.empty() && inorder.empty()) return nullptr; | ||
| int root_value = preorder[0]; | ||
| TreeNode* root = new TreeNode(root_value); | ||
|
|
||
| auto it = find(inorder.begin(), inorder.end(), root_value); | ||
| vector<int> left_tree_inorder(inorder.begin(), it); | ||
| vector<int> right_tree_inorder(it + 1, inorder.end()); | ||
|
|
||
| int left_tree_size = left_tree_inorder.size(); | ||
| vector<int> left_tree_preorder(preorder.begin() + 1, | ||
| preorder.begin() + left_tree_size + 1); | ||
| vector<int> right_tree_preorder(preorder.begin() + left_tree_size + 1, | ||
| preorder.end()); | ||
|
|
||
| root->left = buildTree(left_tree_preorder, left_tree_inorder); | ||
| root->right = buildTree(right_tree_preorder, right_tree_inorder); | ||
| return root; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /** | ||
| * 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) { | ||
| if (preorder_start == preorder_end && inorder_start == inorder_end) return nullptr; | ||
|
|
||
| int root_value = preorder[preorder_start]; | ||
| TreeNode* root = new TreeNode(root_value); | ||
|
|
||
| int inorder_root_index = inorder_start; | ||
| while (inorder[inorder_root_index] != root_value) { | ||
| inorder_root_index++; | ||
| } | ||
|
|
||
| int left_tree_size = inorder_root_index - inorder_start; | ||
| root->left = buildTreeHelper(preorder, preorder_start + 1, preorder_start + left_tree_size + 1, | ||
| inorder, inorder_start, inorder_root_index); | ||
| root->right = buildTreeHelper(preorder, preorder_start + left_tree_size + 1, preorder_end, | ||
| inorder, inorder_root_index + 1, inorder_end); | ||
| return root; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| /** | ||
| * 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) { | ||
| unordered_map<int, int> inorder_value_to_index; | ||
| for (int i = 0; i < inorder.size(); i++) { | ||
| inorder_value_to_index[inorder[i]] = i; | ||
| } | ||
|
|
||
| TreeNode* root = new TreeNode(preorder[0]); | ||
| for (int i = 1; i < preorder.size(); i++) { | ||
| TreeNode* node = root; | ||
| int next_node_value = preorder[i]; | ||
| while (true) { | ||
| if (inorder_value_to_index[next_node_value] < inorder_value_to_index[node->val]) { | ||
| if (!node->left) { | ||
| node->left = new TreeNode(next_node_value); | ||
| break; | ||
| } | ||
| node = node->left; | ||
| } else { | ||
| if (!node->right) { | ||
| node->right = new TreeNode(next_node_value); | ||
| break; | ||
| } | ||
| node = node->right; | ||
| } | ||
| } | ||
| } | ||
| return root; | ||
| } | ||
| }; |
| 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) { | ||
| unordered_map<int, int> inorder_value_to_index; | ||
|
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. unordered_map を使うか map を使うかについて、こちらが参考になると思います。
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. ありがとうございます、参考になりました。 |
||
| for (int i = 0; i < inorder.size(); i++) { | ||
| inorder_value_to_index[inorder[i]] = i; | ||
| } | ||
| return buildTreeHelper(preorder, inorder, 0, 0, preorder.size(), | ||
| inorder_value_to_index); | ||
| } | ||
|
|
||
| private: | ||
| TreeNode* buildTreeHelper(const vector<int>& preorder, const vector<int>& inorder, | ||
| int preorder_start, int inorder_start, int subtree_size, | ||
| unordered_map<int, int>& inorder_value_to_index) { | ||
| if (subtree_size == 0) return nullptr; | ||
| int root_value = preorder[preorder_start]; | ||
| int inorder_root_index = inorder_value_to_index[root_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. atかfindにしたら、const &でマップを渡せますね。
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. コンパイルエラーになったためconstを外した経緯があったんですが、atかfindにすれば良いんですね。ありがとうございます。 |
||
| int left_tree_size = inorder_root_index - inorder_start; | ||
| int right_tree_size = inorder_start + subtree_size - inorder_root_index - 1; | ||
|
|
||
| TreeNode* root = new TreeNode(root_value); | ||
| root->left = buildTreeHelper(preorder, inorder, preorder_start + 1, inorder_start, | ||
| left_tree_size, inorder_value_to_index); | ||
| root->right = buildTreeHelper(preorder, inorder, preorder_start + left_tree_size + 1, | ||
| inorder_root_index + 1, right_tree_size, inorder_value_to_index); | ||
| return root; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /** | ||
| * 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) { | ||
| unordered_map<int, int> inorder_value_to_index; | ||
| for (int i = 0; i < inorder.size(); i++) { | ||
| inorder_value_to_index[inorder[i]] = i; | ||
| } | ||
|
|
||
| TreeNode* root = new TreeNode(preorder[0]); | ||
| queue<NodeAndRange> nodes; | ||
| nodes.emplace(root, numeric_limits<int>::min(), numeric_limits<int>::max()); | ||
| for (int i = 1; i < preorder.size(); i++) { | ||
| int next_node_value = preorder[i]; | ||
| int inorder_next_node_index = inorder_value_to_index.at(next_node_value); | ||
| while (!nodes.empty()) { | ||
| auto [node, lower_index, upper_index] = nodes.front(); nodes.pop(); | ||
| int inorder_cuurent_node_index = inorder_value_to_index.at(node->val); | ||
| if (!(lower_index < inorder_next_node_index && | ||
| inorder_next_node_index < upper_index)) continue; | ||
|
|
||
| if (inorder_next_node_index < inorder_cuurent_node_index) { | ||
| if (node->left) { | ||
| nodes.emplace(node, lower_index, upper_index); | ||
| continue; | ||
| } | ||
| node->left = new TreeNode(next_node_value); | ||
| nodes.emplace(node->left, lower_index, inorder_cuurent_node_index); | ||
| } else { | ||
| if (node->right) { | ||
| nodes.emplace(node, lower_index, upper_index); | ||
| continue; | ||
| } | ||
| node->right = new TreeNode(next_node_value); | ||
| nodes.emplace(node->right, inorder_cuurent_node_index, upper_index); | ||
| } | ||
| if (!node->left || !node->right) nodes.emplace(node, lower_index, upper_index); | ||
| break; | ||
| } | ||
| } | ||
| return root; | ||
| } | ||
|
|
||
| private: | ||
| struct NodeAndRange { | ||
| TreeNode* node; | ||
| int lower_index; | ||
| int upper_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.
これでも良さそうですかね。
int inorder_root_index = find( inorder.begin() + inorder_start, inorder.begin() + inorder_end, root_value ) - inorder.begin();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.
こちらの方がシンプルですね。C++まだ慣れてないので助かります。