-
Notifications
You must be signed in to change notification settings - Fork 0
543. Diameter of Binary Tree #21
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| 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 | ||
|
|
||
| * 今日はちょっと時間がなさそうなので省略 | ||
| 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: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 読み手は、外部からアクセス可能な public: が指定されている関数・変数の定義に興味があると思います。クラスの定義を読んで初めに目に入る上のほうに、 public: な関数・変数を置くことをおすすめします。 参考までにスタイルガイドへのリンクを貼ります。 https://google.github.io/styleguide/cppguide.html#Declaration_Order
上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。 |
||
| int diameter; | ||
|
|
||
| int LongestPath(TreeNode* node) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
| } | ||
| }; | ||
| 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; | ||
| } | ||
| }; |
There was a problem hiding this comment.
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 の手前で定義することをおすすめします。