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
34 changes: 34 additions & 0 deletions arai60/binary-tree-level-order-traversal/README.md
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

見ました。既出のコメント以外の点では、特に問題ないかと思いました。

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## 考察
- 過去に解いたことあり
- 方針
- BFS
- BFSはlevelごとに見ていくのでシンプルに解ける
- 実装としては、キューを1つ使う方法と2つ使う方法が考えられる
- DFS
- 一応、levelを追跡すればOK
- でも、DFSでやるメリットはないと思われる
- まずは、BFSのキューを1つだけ用意する方法で実装

## Step1
- BFSで実装
- time: O(n), space: O(n)

## Step2
- キューを2つ用意する方法でも実装
- `step2_bfs_two_queues.cpp`
- 特にキューである必要もないので、vector2つでも実装
- `step2_bfs_two_vectors.cpp`
- 練習のためにDFSでも実装
- `stpe2_dfs.cpp`
- 他の人のPRを検索
- https://github.com/fhiyo/leetcode/pull/28
- append_if_existsはいいなあと思った
- https://github.com/Mike0121/LeetCode/pull/7
- currentについて
- https://github.com/Mike0121/LeetCode/pull/7#discussion_r1587660995
- たしかに `level_values` だけでも通じるかも

## Step3
- 1回目: 3m27s
- 2回目: 3m12s
- 3回目: 3m05s
33 changes: 33 additions & 0 deletions arai60/binary-tree-level-order-traversal/step1.cpp
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:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return vector<vector<int>>();
vector<vector<int>> answer;
queue<TreeNode*> nodes_to_visit;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

step2_bfs_two_vectors のように、レベルごとに vector を作ったほうが処理が分かりやすいと思いました。

また、変数名の to_visit の部分は、有益な情報が含まれていないように感じました。 nodes で十分だと思います。

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.

ありがとうございます。レベルごとに vector を作る実装を第一選択肢として考えるようにしてみます。
個人的には to_visit があった方が、これから探索するノードということがはっきりすると思いますがいかがでしょうか?
nodes だけだとこれはどんなノードなんだとなりそうな気がします。

nodes_to_visit.push(root);
while (!nodes_to_visit.empty()) {
int level_size = nodes_to_visit.size();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

level_size という変数名ですと、レベルのサイズという意味に感じられ、何を表しているのか分かりにくく感じました。 num_nodes_in_level はいかがでしょうか?

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.

num_nodes_in_level いいですね。step4で修正します。

vector<int> current_level_values;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

個人的には values_in_level としたいですが、 current_level_values でも acceptable だと思います。

for (int i = 0; i < level_size; i++) {
TreeNode* node = nodes_to_visit.front();
nodes_to_visit.pop();
current_level_values.push_back(node->val);
if (node->left) nodes_to_visit.push(node->left);
if (node->right) nodes_to_visit.push(node->right);
}
answer.push_back(move(current_level_values));
}
return answer;
}
};
34 changes: 34 additions & 0 deletions arai60/binary-tree-level-order-traversal/step2_bfs_two_queues.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* 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:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return vector<vector<int>>();
vector<vector<int>> answer;
queue<TreeNode*> nodes_to_visit;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

一つのキューで順不同で push() と pop() をしたりするわけではく、先頭から順にノードを舐められれば十分なため、 queue にする必要が無いように感じました。 step2_bfs_two_vectors のように、 vector 2 つで十分だと思います。

nodes_to_visit.push(root);
while (!nodes_to_visit.empty()) {
vector<int> current_level_values;
queue<TreeNode*> next_level_nodes;
int level_size = nodes_to_visit.size();
for (int i = 0; i < level_size; i++) {
Comment on lines +22 to +23
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

while (!nodes_to_visit.empty()) { のように書いてもいいですね。
こちらの場合nodes_to_visitが空になるまで処理を行うことが明確になる気はします

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.

たしかに while (!nodes_to_visit.empty()) { と書いた方が一目でわかりますね。ありがとうございます。

TreeNode* node = nodes_to_visit.front();
nodes_to_visit.pop();
current_level_values.push_back(node->val);
if (node->left) next_level_nodes.push(node->left);
if (node->right) next_level_nodes.push(node->right);
}
answer.push_back(move(current_level_values));
nodes_to_visit = next_level_nodes;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

= だとコピーが走ります。 std::swap() したほうが処理が軽くなると思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

std::vector::swap のほうが動くバージョン広いですかね?

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.

コピー走りますね。。まだ意識が甘いようです、ありがとうございます。

std::swap, std::vector::swap ともにC++98から使用可能で、std::swap は内部で std::vector::swap を呼び出すようなのでどちらを使っても良さそうです。

Swaps the contents of lhs and rhs. Calls lhs.swap(rhs).

https://en.cppreference.com/w/cpp/container/vector/swap
https://en.cppreference.com/w/cpp/container/vector/swap2

}
return answer;
}
32 changes: 32 additions & 0 deletions arai60/binary-tree-level-order-traversal/step2_bfs_two_vectors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* 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:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return vector<vector<int>>();
vector<vector<int>> answer;
vector<TreeNode*> nodes_to_visit;
nodes_to_visit.push_back(root);
while (!nodes_to_visit.empty()) {
vector<int> current_level_values;
vector<TreeNode*> next_level_nodes;
for (TreeNode* node : nodes_to_visit) {
current_level_values.push_back(node->val);
if (node->left) next_level_nodes.push_back(node->left);
if (node->right) next_level_nodes.push_back(node->right);
}
answer.push_back(move(current_level_values));
nodes_to_visit = next_level_nodes;
}
return answer;
}
};
33 changes: 33 additions & 0 deletions arai60/binary-tree-level-order-traversal/step2_dfs.cpp
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:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return vector<vector<int>>();
vector<vector<int>> answer;
stack<pair<TreeNode*, int>> nodes_to_visit;
nodes_to_visit.push({root, 0});
while (!nodes_to_visit.empty()) {
auto [node, level] = nodes_to_visit.top();
nodes_to_visit.pop();
if (answer.size() == level) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

answer に push_back() する処理を省くため、 map<int, vector> level_to_nodes; として、最後に answer に詰め替えるのも良いかなと思ったのですが、処理がやや重くなるのが微妙にも感じました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

一応、こういう議論があったので貼っておきます
https://discord.com/channels/1084280443945353267/1200089668901937312/1211248049884499988

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.

なるほど。この考えはありませんでした。
たしかに if より while の方が読んでる側からすると安心感がありますね。

answer.push_back({node->val});
} else {
answer[level].push_back(node->val);;
}

if (node->right) nodes_to_visit.push({node->right, level + 1});
if (node->left) nodes_to_visit.push({node->left, level + 1});
}
return answer;
}
};
33 changes: 33 additions & 0 deletions arai60/binary-tree-level-order-traversal/step3.cpp
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:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return {};
vector<vector<int>> answer;
queue<TreeNode*> nodes_to_visit;
nodes_to_visit.push(root);
while (!nodes_to_visit.empty()) {
int level_size = nodes_to_visit.size();
vector<int> level_values;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これで良さそうですかね。
auto& level_values = answer.emplace_back();

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.

この書き方は思いつきませんでした。勉強になります、ありがとうございます。

for (int i = 0; i < level_size; i++) {
auto node = nodes_to_visit.front();
nodes_to_visit.pop();
level_values.push_back(node->val);
if (node->left) nodes_to_visit.push(node->left);
if (node->right) nodes_to_visit.push(node->right);
}
answer.push_back(move(level_values));
}
return answer;
}
};