Skip to content

Add 560. Subarray Sum Equals K.md #17

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
126 changes: 126 additions & 0 deletions 560. Subarray Sum Equals K.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# step 1
まず、以下でTLE
```python
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
result = 0
for left in range(len(nums)):
for right in range(left + 1, len(nums) + 1):
if sum(nums[left:right]) == k:
result += 1
return result
```

多少改善させた次のもTLE
```python
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
result = 0
for left in range(len(nums)):
sub_sum = nums[left]
for right in range(left, len(nums)):
if right != left:
sub_sum += nums[right]
Comment on lines +20 to +23

Choose a reason for hiding this comment

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

sub_sum = 0から始めれば、if right != left:のチェックなしでsub_sumに追加していけます。

Copy link
Owner Author

Choose a reason for hiding this comment

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

確かにそうですね。ありがとうございます!

if sub_sum == k:
result += 1
return result
```

単調性があるわけでないので、部分和を取る尺取法でもなさそうでよくわからず、解答を見る。
先頭から集めた部分和から、その部分和となるprefixの数を記録していけば良いみたい。

```python
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
prefix_subsum = 0
subsum_to_count = {0: 1}
result = 0

for num in nums:
prefix_subsum += num
result += subsum_to_count.get(prefix_subsum - k, 0)

if prefix_subsum not in subsum_to_count:
subsum_to_count[prefix_subsum] = 0
subsum_to_count[prefix_subsum] += 1
return result
```

# step 2
- https://discord.com/channels/1084280443945353267/1233603535862628432/1252232545056063548
- 駅と標高を使って、累積和を高低差みたいに捉えている。
- わかりやすい。今いる地点から標高差kの部分に線を引いて、ぶつかったところと考えれば良さそう。
Copy link

Choose a reason for hiding this comment

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

はじめから [0] = 1 であることがしっくり来ていたらこの話は問題ないと思います。

https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0

- https://github.com/olsen-blue/Arai60/pull/16/files
- cumulative_sumを使っていた。
- 自分はprefix_sumとしていたけど、こっちの方がわかりやすい気がする。
- https://github.com/katataku/leetcode/pull/15/files/7728d62d9ce2b77372315886a9bbcd25dfb0cd32#r1898174496
- num_subarraysの方がわかりやすく感じた。
- subarraySum(nums, k)と与えられた時に、resultだけだと部分和か何かが返ってきそうに感じる

```python
from collections import defaultdict


class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cumulative_sum = 0
cumulative_sum_to_count = defaultdict(int)
cumulative_sum_to_count[0] = 1
subarrays_count = 0
for num in nums:
cumulative_sum += num
subarrays_count += cumulative_sum_to_count.get(
cumulative_sum - k,
0
)
cumulative_sum_to_count[cumulative_sum] += 1
Comment on lines +72 to +76

Choose a reason for hiding this comment

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

cumulative_sum_to_countにdefaultdictを使う場合、シンプルに
subarrays_count += cumulative_sum_to_count[cumulative_sum - k]
と書けそうだなと思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

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

それをすると、cumulative_sum_to_count[cumulative_sum - k] = 0が追加されて不要なメモリ使用が増えそうだから避けようくらいの考えでした。
よくよく考えれば、最悪の場合の空間計算量は変わらないので、提案していただいたものでも問題ありませんね

return subarrays_count
```

# step 3

```python
from collections import defaultdict


class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cumulative_sum = 0
cumulative_sum_to_count = defaultdict(int)
cumulative_sum_to_count[0] = 1

Choose a reason for hiding this comment

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

この行にコメントを付けたいと思いました。
初見だと、なぜnumsを走査していないのに累積和がすでにカウントされているのか?、と思うかもしれません。

Copy link
Owner Author

Choose a reason for hiding this comment

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

個人的には、L88-L91までは初期化の塊と認識していて、コメントの必要は感じていませんでした。
「走査を始める前の、何も数えていない状態の累積和もいれるんだな」くらいのイメージです。

ただ、そのイメージを伝え切れるコードではなかったかもしれません。
cumulative_sum_to_count[cumulative_sum] += 1とする、もしくは、コメントを入れた方が丁寧ですね。

Choose a reason for hiding this comment

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

つけるコメントを考えてみたのですが、なかなかいいものが思いつかなかったので、やっぱりなくてもいいかもしれません。

subarrays_count = 0
for num in nums:
cumulative_sum += num
subarrays_count += cumulative_sum_to_count.get(
cumulative_sum - k,
0
)
cumulative_sum_to_count[cumulative_sum] += 1
return subarrays_count
```

# step 4
コメントの有無、条件分岐を少し簡潔に書くためのコメントをいただいた。

[setdefault](https://docs.python.org/3/library/stdtypes.html#dict.setdefault)
を使ってみる。

```python
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cumulative_sum = 0
cumulative_sum_to_count = {}
cumulative_sum_to_count[0] = 1
num_subarrays_with_sum_k = 0
for num in nums:
cumulative_sum += num
num_subarrays_with_sum_k += cumulative_sum_to_count.get(
cumulative_sum - k, 0
)
cumulative_sum_to_count[cumulative_sum] = (
cumulative_sum_to_count.setdefault(cumulative_sum, 0) + 1
)
return num_subarrays_with_sum_k
```

書きにくい。