Skip to content
Merged
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,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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Solutionインスタンスが作られ、そのインスタンスでbuildTree()が複数回呼ばれた場合を考えるとpreorder_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.

たとえば、HTML Parser だったら、HTML 一つにつきインスタンス一つという設計も自然でしょう。呼ぶ側の気持ちになってどう実装するかを考えるということかと思います。

通常、プログラムというのは、誰かに使って欲しいと思って書かれていて、つまり、それがエンジニアリングをしているということです。ライブラリーの場合は、それは呼ぶ相手のためにエンジニアリングをしているはずです。

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;
}
};
48 changes: 48 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/memo.md
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関数が存在していた


## 他の解法
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

preorderとinorderを使って順に木を構築する方法もあります。

ご参考:https://github.com/kazukiii/leetcode/pull/30/files#diff-0d121db22136b97146c44a3926ea99756ef36fd61caf75dd9d91b5d5a4a484f5

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
38 changes: 38 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/step1.cpp
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()) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

if (inorder.empty()) {
  return nullptr;
}
...

の形の方がコードを読みながら考えることが減って読みやすいかなと思います

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.

@fhiyo
hash_map_step2にて実装しました。
ネストが浅くなる分こちらの方が読みやすいですね。

改めてみてみると最下部に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;
}
};
31 changes: 31 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/step2.cpp
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;
}
};
31 changes: 31 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/step3.cpp
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;
}
};
47 changes: 47 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/step4.cpp
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

preorder_end - preorder_start == inorder_end - inorder_start という制約があるので、これをtree_sizeとかの名前にして、preorder, inorder, preorder_start, inorder_start, tree_size の引数を渡す方が自然な気がしました。

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.

@fhiyo

レビューありがとうございます。
step6に実装してみました。少しスッキリしました。

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

Choose a reason for hiding this comment

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

positionという変数名が曖昧かなと思いました。
これはinorderにおける根を表すindexだと思うので、inorder_root_indexとかでしょうか

あと、indexをいじるのは認知不可が上がるので、inorder, preorderそれぞれのsliceを引き回すようにすると読みやすくなると思いました

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.

@Yoshiki-Iwasa
レビューありがとうございます。inorder_root_index使わせていただきました。

indexをいじるのは認知不可が上がるので、inorder, preorderそれぞれのsliceを引き回すようにすると読みやすくなると思いました

今回複数パターン書いてみましたが、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;
}
};
31 changes: 31 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/step5.cpp
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;
}
};
47 changes: 47 additions & 0 deletions 105.ConstructBinaryTreefromPreorderandInorderTraversal/step6.cpp
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;
}
};
Loading