Skip to content

102. Binary Tree Level Order Traversal#25

Open
seal-azarashi wants to merge 10 commits intomainfrom
binary-tree-level-order-traversal
Open

102. Binary Tree Level Order Traversal#25
seal-azarashi wants to merge 10 commits intomainfrom
binary-tree-level-order-traversal

Conversation

@seal-azarashi
Copy link
Copy Markdown
Owner

- 返り値を格納する変数名は levelOrderTraversal にしない方が良さそう (書いてる自分がよくわからなくなるので)
- node が empty になると constraints にあるのでこれに対処しなければ
- リストの実装型は LinkedList が良さそう
- 後ろに要素を追加していくだけなので、インデックスを使うためのオーバーヘッドが多い ArrayList は除外
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LinkedListよりArrayListの方が多くの場合において速いと思います。

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.

ご指摘ありがとうございます。
これについてですが、 LinkedList では要素追加の度にメモリ領域が確保されるのが主な原因と考えたのですが、こちらいかが思われますでしょうか? ArrayList の末尾への要素追加はインデックスの追加も伴いますが、メモリ領域の確保が行われる回数は少ないので、結果として早くなるのかなと推測しています。あと確保されるメモリ領域が連続しているのも要素追加処理の効率に寄与していそうです。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ArrayListの実装はDynamic arrayになっています。リンクの記事を確認してみてください。

while (!nodes.isEmpty()) {
int currentLevelNodeCount = nodes.size();
List<Integer> valsInCurrentLevel = new LinkedList<>();
for (int i = 0; i < currentLevelNodeCount; i++) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nodes は、同じレベルの値を返り値に詰めるために使い、また次のレベルのノードを格納するという2つの役割を持っていると思います。
次のレベルのノードを格納する役割を別の Queue<TreeNode> に持たせると、役割の分担という意味でより分かりやすくなる気がします。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これ私も賛成ですね。nodes の中に何が入っているかを自然言語で表現すると、割と面倒なことになるはずです。
「currentLevelNodeCount - i 個は、一つ前のレベルが入っていて、そこから残りは次のレベルが入っている」っていうことになりますね。

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.

@goto-untrapped @oda
すいません、対応が大変遅くなりました。
仰るとおり nodes が複数の役割を持った複雑なものになっていたので、次のレベルのノードを格納する方の役割を新しく宣言した newNodes に任せるようにしました。実装は step 4 として別途記載しています: 8ed4aa8

自然言語での表現も素直になったと思います:

  • nodes には現イテレーションで走査対象になるレベルが入っている
  • newNodes には次のイテレーションで走査対象になるレベルが入っている

}

valsInEachLevel.get(level).add(node.val);
int nextLevel = level + 1;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

あえてnextLevelに入れなくても意図は伝わるのかなと思いました。全体的に綺麗なコートだと思いました。

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.

すいません、対応が大変遅くなりました。
ありがとうございます!確かに意図は伝わりますね。ただこちら2箇所で使うので、コードを書いてる際に修正が必要になった際に修正が容易になるように残しておきたいなと思いました。
こういうケースで修正が必要になった際、一部だけ修正を忘れて長い時間詰まるみたいな経験を何度かしてるので、そういったことが起こりづらいようにしたいという意図もあります。


### 再帰関数を用いた DFS アプローチ

スタックオーバーフローのリスクはありますが、練習で書いてみました。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

stack+DFSでも書けますね。

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.

確かに、失念していました。書いてみました: 26d801a

}

private void findValuesInEachLevel(TreeNode node, int level, List<List<Integer>> valsInEachLevel) {
if (valsInEachLevel.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.

ちょっとifだと意図が伝わりづらい気もします(参照)
また、==なのに加えるとなると一瞬「なんでだっけ?」となる気もするので、右辺をlevel + 1にして<とかにしてもいい気もしますが、難しいですね

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.

返信遅くなり失礼しました。リンク先の内容含めて非常に納得出来る指摘でしたので、採用して step 4 に記載しました: 92352eb

また、==なのに加えるとなると一瞬「なんでだっけ?」となる気もするので、右辺をlevel + 1にして<とかにしてもいい気もしますが、難しいですね

これは悩ましいですね... ひとまず今の while 文を使った実装が、「level が大きくて valsInEachLevel が足りない場合、足りるように拡張する」と説明出来る素直な実装になるので、これが考えられる中でベストなのかなと思います。

return valsInEachLevel;
}

private void findValuesInEachLevel(TreeNode node, int level, List<List<Integer>> valsInEachLevel) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

findというよりはfillのような気がします。

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.

すいません遅くなりました。 step 4 に反映しました: 92352eb

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.

7 participants