Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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++;
}
Comment on lines +27 to +30
Copy link
Copy Markdown

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();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらの方がシンプルですね。C++まだ慣れてないので助かります。


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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unordered_map を使うか map を使うかについて、こちらが参考になると思います。
Ryotaro25/leetcode_first60#22 (comment)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます、参考になりました。
chroniumのガイドラインに従うとこのケースの場合はmapで十分と理解しました。

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];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

atかfindにしたら、const &でマップを渡せますね。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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;
};
};