Skip to content

105. Construct Binary Tree from Preorder and Inorder Traversal #43

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

colorbox
Copy link
Owner

hayashi-ay/leetcode#43
shining-ai/leetcode#29
Mike0121/LeetCode#12
sakupan102/arai60-practice#30
YukiMichishita/LeetCode#12
fhiyo/leetcode#31
kazukiii/leetcode#30
Ryotaro25/leetcode_first60#31
Yoshiki-Iwasa/Arai60#33
TORUS0818/leetcode#31
Ryotaro25/leetcode_first60#31
goto-untrapped/Arai60#53
https://github.com/SuperHotDogCat/coding-interview/pull/43/files

範囲情報をスタックから消してみた感想としては、結構非直感的になると思いました。

あるノードの left, right の下にぶら下げるかどうかの条件が、left の場合は、ぶら下げる先のノードの inorder における位置、right の場合は、ぶら下げる先のノードのスタック上の一つ上のノードの inorder における位置なのだけれども、これを分かりやすく説明するのが大変です。

速度の面では、こちらのほうの map や unordered_map のアクセスが増えて遅くなる要素が、あちらのほうの tuple が stack に載って遅くなる要素よりも、強く効くかしら。
https://github.com/nittoco/leetcode/pull/37/files#r1821720967

return buildTreeWithIndex(0, 0, preorder.size(), preorder, inorder);
}

TreeNode* buildTreeWithIndex(int preorder_root_index, int inorder_left, int inorder_right, vector<int>& preorder, vector<int>& inorder) {

Choose a reason for hiding this comment

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

これはpublicでなくてもいいかなと思いました。

Choose a reason for hiding this comment

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

preorderとinorderにどちらもconstをつけると、関数内では変更しないことをこの行で伝えられると思いました。

}
}
root->left = buildTreeWithIndex(preorder_root_index + 1, inorder_left, root_index, preorder, inorder);
root->right = buildTreeWithIndex(preorder_root_index + 1 + (root_index - inorder_left), root_index + 1, inorder_right, preorder, inorder);

Choose a reason for hiding this comment

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

一つ目の引数ですが、ChatGptを使って理解できた(?)レベルでした。
コメントがあってもいいかもです🙇

// get left right tree node count
int left_nodes_count = inorder_root_index;
// split vectors and recursive to left right
vector<int> preorder_left(preorder.begin() + 1, preorder.begin() + 1 + left_nodes_count);

Choose a reason for hiding this comment

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

inorderのルートを起点に左右に分割しvectorに要素を詰め込んでいると思うのですが
毎回全要素をコピーするよりは左右の範囲を管理するインデックスを使った方がコピーコストが下がるのかなと思いました。

int left_nodes_count = inorder_root_index;
// split vectors and recursive to left right
vector<int> preorder_left(preorder.begin() + 1, preorder.begin() + 1 + left_nodes_count);
vector<int> inorder_left(inorder.begin(), inorder.begin() + left_nodes_count);
Copy link

Choose a reason for hiding this comment

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

C++20 からで私はあまり知らないですが、subrange 使う手はありますね。

    TreeNode* buildTree(std::vector<int>& preorder, std::vector<int>& inorder) {
        return buildTreeHelper(
            std::ranges::subrange(preorder.begin(), preorder.end()),
            std::ranges::subrange(inorder.begin(), inorder.end())
        );
    }
    TreeNode* buildTreeHelper(std::ranges::subrange preorder, std::ranges::subrange inorder) {

vector<int> right_preorder(preorder.begin() + 1 + inorder_root_index, preorder.end());
vector<int> right_inorder(inorder.begin() + 1 + inorder_root_index, inorder.end());
root->right = buildTree(right_preorder, right_inorder);

Choose a reason for hiding this comment

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

preorder.begin() + 1 + inorder_root_index や inorder.begin() + inorder_root_index を変数としておくと区間をある境で分けていることが明確になる気もしました。+1 は末尾に書きたいと思いましたが趣味の範囲かもしれません。

class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0) {
Copy link

Choose a reason for hiding this comment

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

if (preorder.empty()) { のほうがシンプルだと思います。

return root;
}
// get index of root in inorder
int inorder_root_index;
Copy link

Choose a reason for hiding this comment

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

int inorder_root_index = std::distance(inorder.begin(), std::find(inorder.begin(), inorder.end(), preorder[0])); のほうがシンプルだと思います。

stack<tuple<TreeNode*, int, int>> nodes_and_limits;
// 番兵の設置、left/rightのlimitはinorderにおける左右部分木の存在可能な限界を示す、番兵の初期値としてmaxを与える
nodes_and_limits.push({&dummy, numeric_limits<int>::max(), numeric_limits<int>::max()});
for (int p: preorder) {
Copy link

Choose a reason for hiding this comment

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

p のあとにスペースを空けることをお勧めします。

class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
map<int, int> value_to_inorder_position;
Copy link

Choose a reason for hiding this comment

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

個人的には value_to_inorder_index のほうが分かりやすいように思いました。

}
stack<TreeNode*> nodes;
//
auto gather_descendants = [&](int node_position) {
Copy link

Choose a reason for hiding this comment

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

node_position が preorder の index か inorder の index か分かりづらく感じました。 preorder_index はいかがでしょうか?

class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {

Copy link

Choose a reason for hiding this comment

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

buildTreeWithIndex() を呼び出しているだけのため、空行は消してしまってよいと思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants