Skip to content
Open
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
175 changes: 175 additions & 0 deletions tree-bst/104.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
- 問題: [104. Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/description/)
- コメント集: [104. Maximum Depth of Binary Tre](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/mobilebasic#h.7b7phcxky0ug)
- 条件
- `The number of nodes in the tree is in the range [0, 10^4].`
- `-100 <= Node.val <= 100`
- 方針
- 選択肢が見えること、その中で何を使うのか?を理由をつけて選択できることが重要
- BFS, DFS が思いつく,思いつく == 書けるなので全てやってみる
- BFSは最短経路を求める時に使うものではあるものの、Queueを使った解法も考えられる
- DFSの方針は以下2つ
- 再帰関数を使う
- Stackを使う
- 時間
- 方針1(シンプルな再帰): 10分, 時間計算量: O(N), 空間計算量: O(N) ※直線の木の場合、最悪 O(N) 個がスタックトレースに乗るから
- 方針2(Stackを使ったDFS): 40分. 方針というよりビルドエラーの解消に苦戦した。お世辞にも綺麗とは言えない.シンプルな方針1を選択した方がいいなと即座にならないといけない.練習としてやってみた. 時間計算量: O(N), 空間計算量: O(N)
- 方針3(Queueを使う方法): 20分、方針2と Stack --> Queue以外同じなので。時間計算量: O(N), 空間計算量: O(N)

## 再帰
- 再帰関数はコールスタックに載せることになるため Stack overflow のリスクがある
- 10^4 くらいであれば再帰関数でも良い、非常にシンプルに書けるので選んだと言える
```java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}

int left = maxDepth(root.left);
int right = maxDepth(root.right);

return Math.max(left, right) + 1;
}
}
```

#### Claudeレビュー
- 一点だけ
- 再帰のコードですが、最初のレビューで指摘した点がそのままです:
```java
java// 今のコード
int left = maxDepth(root.left) + 1;
int right = maxDepth(root.right) + 1;
return Math.max(left, right);

// より読みやすい
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
```
- いや別にどっちでもよくない?と思ったが、可読性という意味で + 1 は一箇所の方がいいと思い直して修正

## Stack
```java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}

Stack<Map<TreeNode, Integer>> nodes = new Stack<>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

cppなので頓珍漢なこと言ってたら申し訳ないんですが、これってpairでなくmapを使用した理由はありますか

Copy link
Copy Markdown
Owner Author

@hiroki-horiguchi-dev hiroki-horiguchi-dev Jun 2, 2026

Choose a reason for hiding this comment

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

Java は標準ライブラリに pair がないからですね、Kotlinには pair どころか triple まであるけど。。
普通に record で書けばよかったのですが、なんで Map 使ったんだろう。
修正します。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Javaにはpairは無いのですね。
知らなかったので的外れなことを言ってしまいました。
kotlinにはあるのですね、勉強になります。

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.

いえいえ、とんでもないです。
コメントいただけて嬉しいです、ありがとうございます。

Map<TreeNode, Integer> nodeAndDepth = new HashMap<>();
nodeAndDepth.put(root, 1);
nodes.push(nodeAndDepth);
int result = 1;

while (!nodes.isEmpty()) {
Map<TreeNode, Integer> entry = nodes.pop();

for (TreeNode node : entry.keySet()) {
if (node.left != null) {
HashMap<TreeNode, Integer> newEntry = new HashMap<>();
newEntry.put(node.left, entry.get(node) + 1);
nodes.push(newEntry);
} else {
result = Math.max(result, entry.get(node));
}

if (node.right != null) {
HashMap<TreeNode, Integer> newEntry = new HashMap<>();
newEntry.put(node.right, entry.get(node) + 1);
nodes.push(newEntry);
} else {
result = Math.max(result, entry.get(node));
}
}
}

return result;
}
}
```

## Queue
```java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}

Queue<Map<TreeNode, Integer>> nodes = new ArrayDeque<>();
Map<TreeNode, Integer> nodeAndDepth = new HashMap<>();
nodeAndDepth.put(root, 1);
nodes.add(nodeAndDepth);
int result = 1;

while(!nodes.isEmpty()) {
Map<TreeNode, Integer> entry = nodes.poll();

for(TreeNode node : entry.keySet()) {
if (node.left != null) {
Map<TreeNode, Integer> newEntry = new HashMap<>();
newEntry.put(node.left, entry.get(node) + 1);
nodes.add(newEntry);
} else {
result = Math.max(result, entry.get(node));
}

if (node.right != null) {
Map<TreeNode, Integer> newEntry = new HashMap<>();
newEntry.put(node.right, entry.get(node) + 1);
nodes.add(newEntry);
} else {
result = Math.max(result, entry.get(node));
}
}
}

return result;
}
}
```