-
Notifications
You must be signed in to change notification settings - Fork 0
Create 560. Subarray Sum Equals K #28
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 変数命名について、countなどより意味のある命名にすると分かりやすくなるなと思いました。 |
||
| } | ||
| }; | ||
|
|
||
|
|
||
| ``` | ||
|
|
||
| - 結局初回の回答で練習 | ||
|
|
||
| ## Step3 *自然な流れ(感覚に落とし込む) | ||
| 1. 6min | ||
| 2. 5min | ||
| 3. 2min | ||
There was a problem hiding this comment.
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にそれぞれどのような意味を持つ値が入るのかが一目でわかるという感覚です。
There was a problem hiding this comment.
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参考にさせていただきます。