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
125 changes: 125 additions & 0 deletions 112_path_sum/answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
問題: https://leetcode.com/problems/path-sum/description/

## step1

問題は
 1.あるTreeNodeとtargetSumという整数が渡される。
 2.TreeNodeのrootからleafへの経路のvalの和でtargetSumになるものがあればtrue、なければfalseを返せ。
というもの。

targetSumからroot->valを引いたものをroot->leftとroot->rightと共に引数にして再帰で関数を回す方法で解いた。

時間計算量:O(N)
空間計算量:O(N)

```cpp
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (!root) {
return false;
}
targetSum -= root->val;
if (targetSum == 0 && !root->left && !root->right) {
return true;
}
bool left_value = hasPathSum(root->left, targetSum);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

left_value という変数名からは、左側の子ノード以下に関する何らかの値というニュアンスを感じました。

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.

そうですね。valueはこの場合boolの値以外もあるので良くなかったです。
has_Path_leftなどがよかったかもしれません。

bool right_value = hasPathSum(root->right, targetSum);
if (left_value || right_value) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

return left_value || right_value;

と書いたほうがシンプルだと思いました。

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.

ありがとうございます。
式の値を返すという考え方がまだ身についていないので積極的に取り入れます。

return true;
} else {
return false;
}
}
};
```

書き方が場当たり的になってしまった(trueを返す時の条件など)。copilotに短縮してもらった。

```cpp
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (!root) return false;

targetSum -= root->val;

if (!root->left && !root->right)
return targetSum == 0;

return hasPathSum(root->left, targetSum) ||
hasPathSum(root->right, targetSum);
}
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

経路が見つかったあとも探索するので、プログラムの動作に若干違和感ありますね。

見つかった時点でTrueを返したほうがわかりやすいかもしれません

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

下の深さ優先のコードのイメージですね

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 (!node->left && !node->right && sum == targetSum)

とすればよかったですが、思いつきませんでした。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

経路が見つかったあとも探索するので、プログラムの動作に若干違和感ありますね。

        return hasPathSum(root->left, targetSum) ||
               hasPathSum(root->right, targetSum);

この部分のことですかね?||は、短絡評価されるので、条件を満たすpathが見つかった時点で打ち切られると思います。

if (!node->left && !node->right && sum == targetSum)

こちらについては、変更の意図がよく分かりませんでした。

Copy link
Copy Markdown

@h-masder h-masder Jun 3, 2026

Choose a reason for hiding this comment

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

はい、あげていただいた箇所の話です。

条件を満たすpathが見つかった時点で打ち切られると思います。

ご指摘いただきありがとうございます。

        bool left_value = hasPathSum(root->left, targetSum);
        bool right_value = hasPathSum(root->right, targetSum);
        if (left_value || right_value) {
            return true;
        } else {
            return false;
        }

を清書したものだと思い込んでいました。

Copy link
Copy Markdown

@h-masder h-masder Jun 3, 2026

Choose a reason for hiding this comment

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

こちらについては、変更の意図がよく分かりませんでした。

私もわかりかねますが、
とはいえ、まずはこちらが何の話をしているのかをちゃんと提示すべきでしたね。すみません。

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.

@rikugame @h-masder
レビューとご指摘ありがとうございます。
最初のh-masderさんのコメントでコメント箇所より下のDFSについての指摘であるということだったので、そこでの変数resultの扱いにおける話だと理解して変更しました。
resultにtrueが入った時点でループが終わらず、全走査をしているからです。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

最初のh-masderさんのコメントでコメント箇所より下のDFSについての指摘である

これは勘違いではないでしょうか。「下の深さ優先のコードのイメージですね」というのは、step3を指していて、早期リターンの例示かと思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@h-masder さんの最初のコメントは、一番上のコードの以下の部分に対して正当なコメントだと思います。

        bool left_value = hasPathSum(root->left, targetSum);
        bool right_value = hasPathSum(root->right, targetSum);
        if (left_value || right_value) {
            return true;
        } else {
            return false;
        }

@nicah4o さん
一方で、Copilotの出したコードが短絡評価を活用したものになっていることについては、大丈夫そうでしょうか?

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.

@rikugame
ありがとうございます。文脈を読めていませんでした。
短絡評価というのは左辺の評価だけで判断できるというものですね。
そちらの変更に目を向けていなかったのでありがたい議論でした。

```

## step2

- https://github.com/attractal/leetcode/pull/37/changes
bfsなどの方法

自分でもstack bfsをやってみた。
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でLIFOに探索をしているので、深さ優先探索(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.

レビューありがとうございます。
気づきませんでしたが確かにそうでした。ありがとうございます。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

幅優先探索に変形してみるとよいと思います

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.

@h-masder

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (!root)
            return false;
        queue<pair<TreeNode*, int>> nodes_and_sums;
        nodes_and_sums.push({root, root->val});
        while (!nodes_and_sums.empty()) {
            auto [node, sum] = nodes_and_sums.front();
            nodes_and_sums.pop();
            if (!node->left && !node->right) {
                if (sum == targetSum)
                    return true;
            }
            if (node->left) {
                nodes_and_sums.push({node->left, sum + node->left->val});
            }
            if (node->right) {
                nodes_and_sums.push({node->right, sum + node->right->val});
            }
        }
        return false;
    }
};

queueにすることで同じレベルの左右nodeを見てその下に向かう形になりますね。
自分が最初bfsといっていたものはある最深部まで行ってからその一つ上のレベルに戻ります。


時間計算量:O(N)
空間計算量:O(N)

```cpp
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (!root)
return false;
stack<pair<TreeNode*, int>> nodes_and_sums;
nodes_and_sums.push({root, 0});
bool result = false;
while (!nodes_and_sums.empty()) {
auto [node, sum] = nodes_and_sums.top();
nodes_and_sums.pop();
sum += node->val;
if (!node->left && !node->right && !result) {
result = (sum == targetSum);
}
if (node->left) {
nodes_and_sums.push({node->left, sum});
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_and_sums.emplace(node->left, sum);

と書くとシンプルになると思います。

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.

レビューありがとうございます。
pushとの違いが分かりました。emplaceは直接構築できるのですね。

}
if (node->right) {
nodes_and_sums.push({node->right, sum});
}
}
return result;
}
};
```

resultにboolで代入せずともtrue条件にsum == targetSumをいれればよかった。

## step3

stackを練習した。

```cpp
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (!root)
return false;
stack<pair<TreeNode*, int>> nodes_and_sums;
nodes_and_sums.push({root, root->val});
while (!nodes_and_sums.empty()) {
auto [node, sum] = nodes_and_sums.top();
nodes_and_sums.pop();
if (!node->left && !node->right) {
if (sum == targetSum)
return true;
}
if (node->left) {
nodes_and_sums.push({node->left, sum + node->left->val});
}
if (node->right) {
nodes_and_sums.push({node->right, sum + node->right->val});
}
}
return false;
}
};
```