diff --git a/Python3/560. Subarray Sum Equals K.md b/Python3/560. Subarray Sum Equals K.md new file mode 100644 index 0000000..158f5a3 --- /dev/null +++ b/Python3/560. Subarray Sum Equals K.md @@ -0,0 +1,90 @@ +## Step 1. Initial Solution + +- 連続する配列の一部の和がある値となるような配列の切り取り方の総数 +- 二重ループで和が一致した時にcountしていく方法を最初に思い付いたがTLE + +```python +class Solution: + def subarraySum(self, nums: List[int], k: int) -> int: + count = 0 + cumulative_sums: List[int] = nums + for i in range(1, len(nums)): + cumulative_sums[i] += cumulative_sums[i-1] + target = k + for i in range(len(nums)): + for sum_to_index in cumulative_sums[i:]: + if target == sum_to_index: + count += 1 + target = cumulative_sums[i] + k + return count +``` + +- 累積和を取っていっても結局探すところで線形時間だと上手くいかない + - 探す対象がHashMapじゃないといけない? + - 考えてみるも答えが分からない +- 答えを見てみると探すところは + - 前の累積和から探す + - 累積和はCountをHashMapに入れておく + + という方針で実装できる + + +```python +class Solution: + def subarraySum(self, nums: List[int], k: int) -> int: + count = 0 + cumulative_sum = 0 + cumulative_sum_to_count: Dict[int, int] = defaultdict(int) + + for i in range(len(nums)): + cumulative_sum += nums[i] + if cumulative_sum == k: + count += 1 + count += cumulative_sum_to_count[cumulative_sum - k] + cumulative_sum_to_count[cumulative_sum] += 1 + return count +``` + +- `if cumulative_sum == k:` の代わりにHashMapに0: 1を入れておく方法もあるが、自然言語的には今の方が違和感なく出来ている気がするのでこのままにする + - パフォーマンス最適化する目的なら変えるべき +- 今回はかなり悩んでしまう時間が長かったので、うだうだ悩む癖をやめたい + - 思考整理→実装のステップで思考整理から詰まっている場合は諦めた方が良い + +### Complexity Analysis + +- 時間計算量:O(n) +- 空間計算量:O(n) + +## Step 2. Alternatives + +- accumulateなる関数がある + - https://docs.python.org/ja/3.13/library/itertools.html#itertools.accumulate + - 他にもitertoolsは知らないものが多そう +- 変数名についてprefix_sumとしている人がいるがよく知らないので調べてみる + + > In [computer science](https://en.wikipedia.org/wiki/Computer_science), the **prefix sum**, **cumulative sum**, **inclusive scan**, or simply **scan** of a sequence of numbers *x*0, *x*1, *x*2, ... is a second sequence of numbers *y*0, *y*1, *y*2, ..., the [sums](https://en.wikipedia.org/wiki/Summation) of [prefixes](https://en.wikipedia.org/wiki/Prefix_(computer_science)) ([running totals](https://en.wikipedia.org/wiki/Running_total)) of the input sequence + > +- defaultdictの第二引数で初期化できる +- 自分の初めの考え方に近いものでも + - 前の累積和から探す→× + - 累積和はCountをHashMapに入れておく→◯ + + ならO(n)で実行できる + + - https://github.com/fuga-98/arai60/pull/17/files + - 結果に求められているのがCountなので、途中で使うデータ構造もCountのHashMapにする可能性を考えないといけない + +## Step 3. Final Solution + +```python +class Solution: + def subarraySum(self, nums: List[int], k: int) -> int: + count = 0 + prefix_sum_to_count: Dict[int, int] = defaultdict(int) + for prefix_sum in accumulate(nums): + if prefix_sum == k: + count += 1 + count += prefix_sum_to_count[prefix_sum - k] + prefix_sum_to_count[prefix_sum] += 1 + return count +```