From ab2dbb435e41621f4b7e17de01e8afcf984af434 Mon Sep 17 00:00:00 2001 From: kazukiii Date: Sun, 21 Jul 2024 00:39:26 -0700 Subject: [PATCH 1/2] =?UTF-8?q?step1,=20step2,=20step3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.md | 42 +++++++++++++++++++ .../step1.cpp | 33 +++++++++++++++ .../step2.cpp | 39 +++++++++++++++++ .../step2_preorder.cpp | 42 +++++++++++++++++++ .../step3.cpp | 40 ++++++++++++++++++ 5 files changed, 196 insertions(+) create mode 100644 arai60/construct-binary-tree-from-preorder-and-inorder-traversal/README.md create mode 100644 arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step1.cpp create mode 100644 arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2.cpp create mode 100644 arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2_preorder.cpp create mode 100644 arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step3.cpp diff --git a/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/README.md b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/README.md new file mode 100644 index 0000000..1f0d736 --- /dev/null +++ b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/README.md @@ -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 diff --git a/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step1.cpp b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step1.cpp new file mode 100644 index 0000000..bc7d489 --- /dev/null +++ b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step1.cpp @@ -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& preorder, vector& 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 left_tree_inorder(inorder.begin(), it); + vector right_tree_inorder(it + 1, inorder.end()); + + int left_tree_size = left_tree_inorder.size(); + vector left_tree_preorder(preorder.begin() + 1, + preorder.begin() + left_tree_size + 1); + vector 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; + } +}; diff --git a/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2.cpp b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2.cpp new file mode 100644 index 0000000..fd9cd78 --- /dev/null +++ b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2.cpp @@ -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& preorder, vector& inorder) { + return buildTreeHelper(preorder, 0, preorder.size(), inorder, 0, + inorder.size()); + } + +private: + TreeNode* buildTreeHelper(const vector& preorder, int preorder_start, int preorder_end, + const vector& 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; + } +}; diff --git a/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2_preorder.cpp b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2_preorder.cpp new file mode 100644 index 0000000..5e51e03 --- /dev/null +++ b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step2_preorder.cpp @@ -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& preorder, vector& inorder) { + unordered_map 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; + } +}; diff --git a/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step3.cpp b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step3.cpp new file mode 100644 index 0000000..5d3876f --- /dev/null +++ b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step3.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: + TreeNode* buildTree(vector& preorder, vector& inorder) { + unordered_map inorder_value_to_index; + 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& preorder, const vector& inorder, + int preorder_start, int inorder_start, int subtree_size, + unordered_map& 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]; + 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; + } +}; From ea6c089385c2259524bc6fd631defe0a87c36dd8 Mon Sep 17 00:00:00 2001 From: kazukiii Date: Sat, 27 Jul 2024 00:19:47 -0700 Subject: [PATCH 2/2] =?UTF-8?q?step4:=20queue=E3=82=92=E4=BD=BF=E3=81=A3?= =?UTF-8?q?=E3=81=9F=E5=AE=9F=E8=A3=85=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../step4_preorder_with_queue.cpp | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step4_preorder_with_queue.cpp diff --git a/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step4_preorder_with_queue.cpp b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step4_preorder_with_queue.cpp new file mode 100644 index 0000000..5c3e024 --- /dev/null +++ b/arai60/construct-binary-tree-from-preorder-and-inorder-traversal/step4_preorder_with_queue.cpp @@ -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& preorder, vector& inorder) { + unordered_map 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 nodes; + nodes.emplace(root, numeric_limits::min(), numeric_limits::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; + }; +};