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
132 changes: 132 additions & 0 deletions 560/560. Subarray Sum Equals K.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/description/)
## Step1
### 問題意図の考察
- 問題文の確認
- いくつか分からない語があった。 subarrays, contiguous連続?
- 整数配列'nums'と整数'k'が与えられ、合計がちょうど整数kと同じsubarraysの合計の数を返す。例を見るが例1が当てはまらないように感じて、?
- 和訳調べる
- subarrays(部分配列), contiguous(連続). ここでの部分配列とは、配列の連続した要素からなる、空ではない区間のことを指す。
- 各例の意味がわかった。
- ex1. nums[0]+nums[1] = 2(k), nums[1]+nums[2] = 2(k) で連続する配列がkと同じ部分配列の数を返している。
- ex2. nums[0]+nums[1] = 3(k), nums[2] = 3(k)

- 制約の確認
- 1 <= nums.length <= 2 * 10^4 (20,000)
- -1000 <= nums[i] <= 1000
- -10^7 <= k <= 10^7 (-10,000,000 ~ 10,000,000)

- 問題意図
- 連続する部分配列の扱い
- subarrayを見つけるのではなく、その個数を返す
- 累積和がkとなる時の数を記録する。-> 後述:部分的な思考

### 解法を考える。
- 思いつかなかったので、他の人の回答を見る。

初回の回答
```cpp
#include <unordered_map>
#include <vector>

class Solution {
public:
int subarraySum(const std::vector<int>& nums, int k) {
std::unordered_map<int, int> prefix_count;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

map系の変数名は key_to_value といった命名が個人的には好みです。(prefix_to_count)変数名を見るとkey,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.

@t9a-dev
ありがとうございます。
今までkey_to_valueみたいな命名を何回か使ってたんですが。map系だからなんですね。すごく分かりやすくなりました。prefix_to_count参考にさせていただきます。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

prefix_sumが出てきている文脈なので推測はできますが、単にprefix_countだと接頭辞を数える?のように一瞬感じました。prefix sumで一つの専門用語のように思うので、個人的にはprefix_sum_to_countのようなものが好みです。

prefix_count[0] = 1;

int prefix_sum = 0;
int result = 0;

for (int num : nums) {
prefix_sum += num;
auto it = prefix_count.find(prefix_sum - k);
if (it != prefix_count.end()) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

C++20以降では要素の存在判定にはstd::map::containsも使えるかと思います。

result += it->second;
}
++prefix_count[prefix_sum];
}
return result;
}
};

```

## Step2
- 改善点
- 初めの問題意図の **累積和がkとなる時の数を記録する。** が部分的、追加すべき。
- 累積和そのものがkになったらcount, 累積和 - kが過去に何回あったかを数える。

- 他の方のコードを読む
- https://github.com/5ky7/arai60/pull/17/commits/592a112fcdb82cc0c76a331acb4bad27db1bf2f1
- https://github.com/komdoroid/arai60/pull/6/commits/908a229ed1f129a2749065ce0a6eb3ff50d75cba
- odaさんの例がわかりやすかった。
- https://discord.com/channels/1084280443945353267/1233603535862628432/1252232545056063548
- https://discord.com/channels/1084280443945353267/1206101582861697046/1208414507735453747
- https://github.com/Hurukawa2121/leetcode/pull/16/commits/2525739fd213a9509369768ba21c4c61d4139c07
- キャッシュ利用などにも言及していた、まだそこまで考えれていないし、どの程度必要なのかも分からない。
>> - 累積和を計算するのに C++17 からの `std::exclusive_scan()` が使える。
>> - https://en.cppreference.com/w/cpp/algorithm/exclusive_scan
>> - ここで C++17 から`std::execution` のアルゴリズムの並列実行を許可する実行ポリシーがあることを知る。
>> - https://cpprefjp.github.io/reference/execution/execution/execution_policy.html#:~:text=parallel_policy%20/%20par
>> - 確かに、排他制御をユーザが担うのかプログラムが担うのかを区別する必要がある。
- https://github.com/5103246/LeetCode_Arai60/pull/16/commits/f3361f99bf44ff1f829d5a5320b67a1f6dbaec6b
>> いくつかの解法を書かれてて分かりやすかった。

- O(n^3)パターン
```cpp
#include <vector>

class Solution {
public:
int subarraySum(const std::vector<int>& nums, int k) {
const int n = static_cast<int>(nums.size());
int result = 0;
for (int begin = 0; begin < n; ++begin) {
for (int end = begin; end < n; ++end) {
int sum = 0;
for (int i = begin; i <= end; ++i) {
sum += nums[i];
}
if (sum == k) {
++result;
}
}
}
return result;
}
};


```

- O(n^2)パターン
```cpp
#include <vector>

class Solution {
public:
int subarraySum(const std::vector<int>& nums, int k) {
const int n = static_cast<int>(nums.size());
int result = 0;
for (int begin = 0; begin < n; ++begin) {
int sum = 0;
for (int end = begin; end < n; ++end) {
sum += nums[end];
if (sum == k) {
++result;
}
}
}
return result;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

変数命名について、countなどより意味のある命名にすると分かりやすくなるなと思いました。

}
};


```

- 結局初回の回答で練習

## Step3 *自然な流れ(感覚に落とし込む)
1. 6min
2. 5min
3. 2min