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
45 changes: 45 additions & 0 deletions 543_diameter_of_binary_tree/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 543. Diameter of Binary Tree

https://leetcode.com/problems/diameter-of-binary-tree/

## Comments

### step1

* とりあえずあまり時間がない日だったので、2 分考えて自信がなかった (diameter の更新は別途して、再帰関数の返り値は left, right のいずれかどちらかの path だけの長さを返せばいいだろう、くらいは考えた) LeetCode の回答の方針で書いてみたが -1 を返していたり、+2 していたりで謎の実装。step2 で修正する。

### step2

* `Solution1`step1 の書き直し。LongestPath という名前ならまあ -1 ではなくて 0 が返ってほしい
* https://github.com/Kitaken0107/GrindEasy/pull/17/files
* 参照透過性の話
* step1 の実装だと、`LongestPath` が単体で呼ばれると `diameter` がリセットされないので困る。一応 `private` にしており、外部からは呼ばれない想定だが、あまりよくないかな?
* Python で書いていると確かにやってしまいそうな実装のような気はする。
* 上記の、"再帰関数の返り値は left, right のいずれかどちらかの path だけの長さを返せばいいだろう" くらいの思考をたどると、ペアを返すという発想にはなりにくい気がする。
* みんながアクセスできる場所に diameter を保存しておこう -> じゃあインスタンスメンバかな、みたいな
* ただ一方で、diameter を `Solution` クラスのインスタンスメンバに持つ、というのはだいぶ違和感があり、そっちの方向から気づくかもしれない。
* https://discord.com/channels/1084280443945353267/1206101582861697046/1230424716645240892
* `Solution2`: C++ なので参照で書いてみる。

Python で書くならこんな感じにしそう (C++ の参照のコード `step2.Solution2`そのまま)。関数内関数とかいいんじゃないですか。普段あまり使わないけど、今回は使ってもいい気がする。ペアで返すのも悪くはないと思う。

```py
class SolutionPy:
def diameterOfBinaryTree(self, root):
def traverse(node):
if node is None:
return 0
nonlocal diameter
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

inner function の内部で使用する外側の変数を、 inner function よりあとに書くと、変数の定義を確認するために目線を上下に移動しなければならなくならず、読み手にとって煩わしく感じられる場合があります。 inner function の手前で定義することをおすすめします。

left = traverse(node.left)
right = traverse(node.right)
diameter = max(diameter, left + right)
return max(left, right) + 1

diameter = 0
traverse(root)
return diameter
```

### step3

* 今日はちょっと時間がなさそうなので省略
55 changes: 55 additions & 0 deletions 543_diameter_of_binary_tree/step1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* 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 {
private:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

読み手は、外部からアクセス可能な public: が指定されている関数・変数の定義に興味があると思います。クラスの定義を読んで初めに目に入る上のほうに、 public: な関数・変数を置くことをおすすめします。

参考までにスタイルガイドへのリンクを貼ります。

https://google.github.io/styleguide/cppguide.html#Declaration_Order

Group similar declarations together, placing public parts earlier.

上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。

int diameter;

int LongestPath(TreeNode* node) {
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 (node == nullptr) {
return -1;
}
int left_path = LongestPath(node->left);
int right_path = LongestPath(node->right);
diameter = std::max(diameter, left_path + right_path + 2);
return std::max(left_path, right_path) + 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.

この空行は処理の区切りを視覚的に分かりやすくしたもの等ではく、読み手にとって有益な情報を与えないため、無いほうが良いと思います。

}
public:
int diameterOfBinaryTree(TreeNode* root) {
diameter = 0;
LongestPath(root);
return diameter;
}
};


class Solution2 {
private:
int diameter;

int LongestPath(TreeNode* node) {
if (node == nullptr) {
return 0;
}
int left_path = LongestPath(node->left);
int right_path = LongestPath(node->right);
diameter = std::max(diameter, left_path + right_path);
return std::max(left_path, right_path) + 1;

}
public:
int diameterOfBinaryTree(TreeNode* root) {
diameter = 0;
LongestPath(root);
return diameter;
}
};
53 changes: 53 additions & 0 deletions 543_diameter_of_binary_tree/step2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* 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 Solution1 {
private:
int diameter;

int LongestPath(TreeNode* node) {
if (node == nullptr) {
return 0;
}
int left_path = LongestPath(node->left);
int right_path = LongestPath(node->right);
diameter = std::max(diameter, left_path + right_path);
return std::max(left_path, right_path) + 1;

}
public:
int diameterOfBinaryTree(TreeNode* root) {
diameter = 0;
LongestPath(root);
return diameter;
}
};


class Solution2 {
private:
int Traverse(TreeNode* node, int& diameter) {
if (node == nullptr) {
return 0;
}
int left_path = Traverse(node->left, diameter);
int right_path = Traverse(node->right, diameter);
diameter = std::max(diameter, left_path + right_path);
return std::max(left_path, right_path) + 1;

}
public:
int diameterOfBinaryTree(TreeNode* root) {
int diameter = 0;
Traverse(root, diameter);
return diameter;
}
};
Empty file.