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
66 changes: 66 additions & 0 deletions hashmap/560.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
- 問題: [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/description/)
- コメント集: [](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/mobilebasic#h.e5dwa7yj3tv0)
- [しっくりこない](https://discord.com/channels/1084280443945353267/1233603535862628432/1252232545056063548)
- 私もしっくりこなかったのでちょっと寝かせてしまった。
Copy link
Copy Markdown

@h-masder h-masder May 19, 2026

Choose a reason for hiding this comment

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

わたしもはじめよくわからなかったので、図にしてみました。
https://github.com/h-masder/Arai60/pull/17/changes の560_Subarray_Sum_Equals_K/subarraySum_logic.pngです

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.

ありがとうございます。
金銭で例えるのはより身近でわかりやすいと思いました。
自分が納得できる例に問題を言い換えるのも、問題を解く上で重要ですね。

- 問題のキモは3つあると思う
1. 累積和を使って `prefix[j] - prefix[i] = k` となる2点間を探せばいいと気がつくこと
- これを式変形して、`prefix[j] - k = prefix[i]` とすること
- つまり、今(j)までの累積和からkを引いた値が、過去 nums[i] までの累積和と一致していれば、i,j の2点間の差がkだと言えること
2. i,j とあたかも二重ループのような話を i は j の過去であると捉え、HashMap の key に nums[i] までの累積和を記録し、value に出現回数を記録すればいいのだ、と気がつくこと
3. nums について、「あ、こういうケースがあるな」で思いついたら上記の理屈に当てはめて考えるので、直感とは違う処理をしているように感じる
1. 特に番兵(key:0, value:1)のところ
2. 例えば、`nums = [1,6,3], k=3, prefix[0,1,7,10]` の時
3. `nums[2] = k` がある、これは即カウントせねば、と直感的に思うんだけれど、、、
4. 上記の考え方をすると、prefix[2] - 3 = 7、つまり prefix[2], prefix[1] 間の差が3であるに言い換えられており、これをプログラム上表現しなければいけないと思うこと
- [パフォーマンス不足...](https://github.com/Hurukawa2121/leetcode/pull/16#discussion_r1898332261)
- 私の所属がSIerとかいうところで、バッチがこうなりがちだと思った(早く抜けたい。。)
- [自然言語で説明できる?](https://discord.com/channels/1084280443945353267/1300342682769686600/1357378682163036160)
- 意識して書くようにしている
- 条件
- 1 <= nums.length <= 2 * 104
- -1000 <= nums[i] <= 1000
- -107 <= k <= 107
- 方針
- ブルートフォース: O(N^2)
- i,j で全通り走査する
- j = i + 1 かつ j < nums.size() を満たすように回すところが注意点くらいか
- 累積和を使う: O(N)
- 駅の標高と考えてみると、標高差がkとなる2点間を見つければいいとわかる
- つまり、prefix[j] - prefix[i] = k となる2点を見つける
- これは prefix[j] - k = prefix[i] と変形できる
- prefix[i] を記録し続けながら、prefix[j] - k が登場する回数をカウントする
- prefix[j] = k となる場合、つまり出発点からjまでの累積和がちょうどkになる場合をカウントするため、辞書に key:0, value:1を記録しておく
- この問題の肝はコメント集のところで触れている
- 時間計算量
- 方針1 O(N^2)
- 方針2 O(N)
- 空間計算量
- 方針1 O(1)
- 方針2 O(N): numsのサイズ分

# 1st
```java
class Solution {
public int subarraySum(int[] nums, int k) {

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

@hiroki-horiguchi-dev hiroki-horiguchi-dev May 19, 2026

Choose a reason for hiding this comment

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

ありがとうございます。
そうですね、書き直した時に空いていたようです。修正します。

Map<Integer, Integer> prefixCount = new HashMap<>();
prefixCount.put(0, 1);
int prefixNum = 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私は prefixSum の方が実態を表す変数名になると思いました。

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.

ありがとうございます。おっしゃる通りだと思います。

int result = 0;

for(int num : nums) {
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 for のあとにスペースが空いているものと空いていないものとで混在しているのが気になりました。

参考までにスタイルガイドへのリンクを共有いたします。

https://google.github.io/styleguide/javaguide.html#s4.6.2-horizontal-whitespace

Separating any keyword, such as if, for or catch, from an open parenthesis (() that follows it on that line

なお、このスタイルガイドは“唯一の正解”というわけではなく、数あるガイドラインの一つに過ぎません。チームによって重視される書き方や慣習も異なります。そのため、ご自身の中に基準を持ちつつも、最終的にはチームの一般的な書き方に合わせることをお勧めします。

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 for の前後は空けるでコードを書いてきたので修正します。

prefixNum += num;
int target = prefixNum - k;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

complement(補完値、ついになる値)と名付けている方もいらっしゃいました。

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.

ありがとうございます。
claudeも同様の指摘をしてきたのですが、complementは今回私はあまりしっくりこなかった記憶があります。

if (prefixCount.containsKey(target)) {
result += prefixCount.get(target);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

getOrDefault を使えば1行になります
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Map.html

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.

なるほど、確かにそうですね。getOrDefault() で1行なら if で明示的に書くより、私もいいと思います。
取り込みたいと思います。

}
prefixCount.put(prefixNum, prefixCount.getOrDefault(prefixNum, 0) + 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.

prefixCount.merge(prefixNum, 1, Integer::sum);

とも書けるみたいです

Copy link
Copy Markdown
Owner Author

@hiroki-horiguchi-dev hiroki-horiguchi-dev May 19, 2026

Choose a reason for hiding this comment

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

ありがとうございます、claudeがレビューで出してきました。
このmerge関数ですが、初見で何しているかよくわからないなあと思ったので、採用見送りました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Goは map[key]++ と書けるのですが、Javaはマップ要素のインクリメントを簡潔に実行する方法なさそうですね

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.

Go 便利ですね。
hashmap 関係の問題は getOrDefault() を毎回書いてました、少し冗長に感じますよね

}

return result;
}
}
```

# Cluadeレビュー
- O(N)の方針は全く思いつかなかったので、壁打ちしつつやったため最後に受けるレビューは特になし