From 0a5c36efba618b7f378b80830e8d2c743d50b4a8 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Tue, 29 Jul 2025 23:23:07 +0900 Subject: [PATCH 1/2] finish --- 152.MaximumProductSubarray/brute_force.cpp | 17 ++++++++++ 152.MaximumProductSubarray/memo.md | 36 ++++++++++++++++++++++ 152.MaximumProductSubarray/step1.cpp | 19 ++++++++++++ 152.MaximumProductSubarray/step2.cpp | 21 +++++++++++++ 152.MaximumProductSubarray/step2_2.cpp | 21 +++++++++++++ 152.MaximumProductSubarray/step3.cpp | 21 +++++++++++++ 6 files changed, 135 insertions(+) create mode 100644 152.MaximumProductSubarray/brute_force.cpp create mode 100644 152.MaximumProductSubarray/memo.md create mode 100644 152.MaximumProductSubarray/step1.cpp create mode 100644 152.MaximumProductSubarray/step2.cpp create mode 100644 152.MaximumProductSubarray/step2_2.cpp create mode 100644 152.MaximumProductSubarray/step3.cpp diff --git a/152.MaximumProductSubarray/brute_force.cpp b/152.MaximumProductSubarray/brute_force.cpp new file mode 100644 index 0000000..8aa9d27 --- /dev/null +++ b/152.MaximumProductSubarray/brute_force.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + int maxProduct(vector& nums) { + if (nums.empty()) { + return 0; + } + int max_product = numeric_limits::min(); + for (int i = 0; i < nums.size(); i++) { + int temp = 1; + for (int j = i; j < nums.size(); j++) { + temp *= nums[j]; + max_product = max(max_product, temp); + } + } + return max_product; + } +}; diff --git a/152.MaximumProductSubarray/memo.md b/152.MaximumProductSubarray/memo.md new file mode 100644 index 0000000..28d88ef --- /dev/null +++ b/152.MaximumProductSubarray/memo.md @@ -0,0 +1,36 @@ +## ステップ1 +まず思いついた解法はbrute forceで愚直に積を求める方法 +これだと時間計算量は、O(n^2)となる +nums.lengthは2 * 10 ^ 4なので4 * 10 ^ 8 C++だとギリギリ1秒ないに処理できそう + +各ステップで最大になるタイミングを追いかける +・あるnums[i]でリセットする場合(負の数を奇数個含む場合はnums[i]の方が大きくなることがある) +・正の数ばかりがsubarrayに含まれる場合 +・負の数偶数個含む場合 +単に正の数だけ追うのではなく負の数も追いかけると1ループで見つけられそう +時間計算量はO(n) +空間計算量はO(1) + +acceptまで12分 + +配列が空の場合にreturn 0とする。 +本当はありえない数字を返したかった。エラーメッセージを表示するなどでも良さそう。 + +## ステップ2 +step1の変数名が長いので、変更 + +maxとminの使い方変更 +initializer listsを使うことで複数の値でも使うことができる +https://cplusplus.com/reference/algorithm/max/ + +## ステップ3 +**3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** + +## 他の解法 +負の数が偶数個あると最大になりうる特性を活かして途中でswapすることで +自分のstep1で行った3パターンから2パターンへ比較回数を減らすことができる(step2_2で実装) +これは初見で思いつくことが難しそうなので愚直に比較したい +https://leetcode.com/problems/maximum-product-subarray/solutions/48230/possibly-simplest-solution-with-o-n-time-complexity/ + +## Discorなど + diff --git a/152.MaximumProductSubarray/step1.cpp b/152.MaximumProductSubarray/step1.cpp new file mode 100644 index 0000000..8924310 --- /dev/null +++ b/152.MaximumProductSubarray/step1.cpp @@ -0,0 +1,19 @@ +class Solution { +public: + int maxProduct(vector& nums) { + if (nums.empty()) { + return 0; + } + int max_product = nums[0]; + int max_product_so_far = nums[0]; + int min_product_so_far = nums[0]; + for (int i = 1; i < nums.size(); i++) { + int temp_max_so_far = max(nums[i], max(max_product_so_far * nums[i], min_product_so_far * nums[i])); + min_product_so_far = min(nums[i], min(max_product_so_far * nums[i], min_product_so_far * nums[i])); + max_product_so_far = temp_max_so_far; + max_product = max(max_product, max_product_so_far); + } + + return max_product; + } +}; diff --git a/152.MaximumProductSubarray/step2.cpp b/152.MaximumProductSubarray/step2.cpp new file mode 100644 index 0000000..8041ed7 --- /dev/null +++ b/152.MaximumProductSubarray/step2.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + int maxProduct(vector& nums) { + if (nums.empty()) { + return 0; + } + int max_product = nums[0]; + int current_max = nums[0]; + int current_min = nums[0]; + for (int i = 1; i < nums.size(); i++) { + // current_maxの数字は次の行で使うので一旦退避 + int temp = max({nums[i], current_max * nums[i], current_min * nums[i]}); + current_min = min({nums[i], current_max * nums[i], current_min * nums[i]}); + + current_max = temp; + max_product = max(max_product, current_max); + } + + return max_product; + } +}; diff --git a/152.MaximumProductSubarray/step2_2.cpp b/152.MaximumProductSubarray/step2_2.cpp new file mode 100644 index 0000000..870fda1 --- /dev/null +++ b/152.MaximumProductSubarray/step2_2.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + int maxProduct(vector& nums) { + if (nums.empty()) { + return 0; + } + int max_product = nums[0]; + int max_product_so_far = nums[0]; + int min_product_so_far = nums[0]; + for (int i = 1; i < nums.size(); i++) { + if (nums[i] < 0) { + swap(max_product_so_far, min_product_so_far); + } + max_product_so_far = max(nums[i], max_product_so_far * nums[i]); + min_product_so_far = min(nums[i], min_product_so_far * nums[i]); + max_product = max(max_product, max_product_so_far); + } + + return max_product; + } +}; \ No newline at end of file diff --git a/152.MaximumProductSubarray/step3.cpp b/152.MaximumProductSubarray/step3.cpp new file mode 100644 index 0000000..e7ac00c --- /dev/null +++ b/152.MaximumProductSubarray/step3.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + int maxProduct(vector& nums) { + if (nums.empty()) { + return 0; + } + + int max_product = nums[0]; + int current_max = nums[0]; + int current_min = nums[0]; + for (int i = 1; i < nums.size(); i++) { + int temp = max({nums[i], current_max * nums[i], current_min * nums[i]}); + current_min = min({nums[i], current_max * nums[i], current_min * nums[i]}); + + current_max = temp; + max_product = max(max_product, current_max); + } + + return max_product; + } +}; From ad649ecdf83aaaf550aee8e16f59eda0c3c628a1 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Wed, 30 Jul 2025 22:36:40 +0900 Subject: [PATCH 2/2] finish --- 15.3Sum/brute_force.cpp | 25 +++++++++++++++++++++++ 15.3Sum/memo.md | 45 +++++++++++++++++++++++++++++++++++++++++ 15.3Sum/sort.cpp | 44 ++++++++++++++++++++++++++++++++++++++++ 15.3Sum/step1.cpp | 32 +++++++++++++++++++++++++++++ 15.3Sum/step2.cpp | 28 +++++++++++++++++++++++++ 15.3Sum/step3.cpp | 26 ++++++++++++++++++++++++ 6 files changed, 200 insertions(+) create mode 100644 15.3Sum/brute_force.cpp create mode 100644 15.3Sum/memo.md create mode 100644 15.3Sum/sort.cpp create mode 100644 15.3Sum/step1.cpp create mode 100644 15.3Sum/step2.cpp create mode 100644 15.3Sum/step3.cpp diff --git a/15.3Sum/brute_force.cpp b/15.3Sum/brute_force.cpp new file mode 100644 index 0000000..22cf12c --- /dev/null +++ b/15.3Sum/brute_force.cpp @@ -0,0 +1,25 @@ +class Solution { +public: + vector> threeSum(vector& nums) { + if (nums.empty()) { + return {}; + } + set> unique_triplets; + for (int i = 0; i < nums.size(); i++) { + for (int j = 0; j < nums.size(); j++) { + for (int k = 0; k < nums.size(); k++) { + if (i == j || j == k || k == i) { + continue; + } + if (nums[i] + nums[j] + nums[k] == 0) { + vector triplet = {nums[i], nums[j], nums[k]}; + sort(triplet.begin(), triplet.end()); + unique_triplets.insert(triplet); + } + } + } + } + + return vector>(unique_triplets.begin(), unique_triplets.end()); + } +}; diff --git a/15.3Sum/memo.md b/15.3Sum/memo.md new file mode 100644 index 0000000..5e66495 --- /dev/null +++ b/15.3Sum/memo.md @@ -0,0 +1,45 @@ +## ステップ1 +Brute forceは比較的簡単に思いついた +3つの数字を追うように3つのループを使い、合計が0の場合に +vectorに入れてsortしそれをsetに入れることで重複を消す +時間計算量はO(n^3 * log n) +brute_force.cppに実装 + +nums[i]とnums[j]が決まれば残りの数が決まる. +残りの数をcomplimentとすると +nums[i] + nums[j] + compliment = 0 +compliment = -nums[i] - nums[j] + +jをループでまわす際に、setを使ってすでに通りすぎたnums[j]を記録していく +complimentがset内に入っていれば、合計して0になる組が存在するということ +これをvectorに入れてsortしそれをsetに入れることで重複を消す +時間計算量はO(n^2 * log n) +3000 = 3 * 10^3 +≒ 9 * 10^6 * 3 +≒ 10^7なので許容ないか +acceptまで20分 + +## ステップ2 +変数名を微調整 + +最初に入力値をsortしてしまう方法もある。 +https://leetcode.com/problems/3sum/editorial/ +sort.cppに実装 + +3つの数のうちどれか一つは必ず負の数であることを利用する +ひとつ目の数字が決まったら、その次の数字と最後の数字を見ていく +合計が0になるまで前後から狭める + +i == 0の場合とnums[i] != nums[i - 1]の場合に呼び出すものが同じなので +纏めるか迷うところ。比較している対象は異なる + +この解法が最も素直か + +## ステップ3 +**3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** + +## 他の解法 + + +## Discordなど + diff --git a/15.3Sum/sort.cpp b/15.3Sum/sort.cpp new file mode 100644 index 0000000..7fca97a --- /dev/null +++ b/15.3Sum/sort.cpp @@ -0,0 +1,44 @@ +class Solution { +public: + vector> threeSum(vector& nums) { + sort(nums.begin(), nums.end()); + vector> triplets; + for (int i = 0; i < nums.size(); i++) { + if (nums[i] > 0) { + break; + } + if (i == 0) { + FindTriplet(nums, i, triplets); + continue; + } + if (nums[i] != nums[i - 1]) { + FindTriplet(nums, i, triplets); + } + } + return triplets; + } + +private: + void FindTriplet(vector& nums, int index, vector>& triplets) { + int left = index + 1; + int right = nums.size() - 1; + while (left < right) { + int sum = nums[index] + nums[left] + nums[right]; + if (sum < 0) { + left++; + } else if (sum > 0) { + right--; + } else { + triplets.push_back({nums[index], nums[left], nums[right]}); + left++; + while (left < right && nums[left] == nums[left - 1]) { + left++; + } + right--; + while (left < right && nums[right] == nums[right + 1]) { + right--; + } + } + } + } +}; diff --git a/15.3Sum/step1.cpp b/15.3Sum/step1.cpp new file mode 100644 index 0000000..63a6919 --- /dev/null +++ b/15.3Sum/step1.cpp @@ -0,0 +1,32 @@ +class Solution { +public: + vector> threeSum(vector& nums) { + set> unique_triplets; + // 3組の内ひとつ目の数字をユニークにするために使用 + set first_nums; + for (int i = 0; i < nums.size(); i++) { + if (first_nums.contains(nums[i])) { + continue; + } + first_nums.insert(nums[i]); + + // nums[i]に対応する(nums[j], complement)のペアを探すために + // 既にnums[j]として通りすぎた数字を記録する。 + set seen; + for (int j = i + 1; j < nums.size(); j++) { + int complement = -nums[i] - nums[j]; + if (!seen.contains(complement)) { + seen.insert(nums[j]); + continue; + } + + vector triplet = {nums[i], nums[j], complement}; + sort(triplet.begin(), triplet.end()); + unique_triplets.insert(triplet); + } + } + + // vectorに変換して返す + return vector>(unique_triplets.begin(), unique_triplets.end()); + } +}; diff --git a/15.3Sum/step2.cpp b/15.3Sum/step2.cpp new file mode 100644 index 0000000..c80ae45 --- /dev/null +++ b/15.3Sum/step2.cpp @@ -0,0 +1,28 @@ +class Solution { +public: + vector> threeSum(vector& nums) { + set> unique_triplets; + set used_first_nums; + for (int i = 0; i < nums.size(); i++) { + if (used_first_nums.contains(nums[i])) { + continue; + } + used_first_nums.insert(nums[i]); + + set seen; + for (int j = i + 1; j < nums.size(); j++) { + int complement = -nums[i] - nums[j]; + if (!seen.contains(complement)) { + seen.insert(nums[j]); + continue; + } + + vector triplet = {nums[i], nums[j], complement}; + sort(triplet.begin(), triplet.end()); + unique_triplets.insert(triplet); + } + } + + return vector>(unique_triplets.begin(), unique_triplets.end()); + } +}; diff --git a/15.3Sum/step3.cpp b/15.3Sum/step3.cpp new file mode 100644 index 0000000..923247b --- /dev/null +++ b/15.3Sum/step3.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + vector> threeSum(vector& nums) { + set> unique_triplets; + set used_first_nums; + for (int i = 0; i < nums.size(); i++) { + if (used_first_nums.contains(nums[i])) { + continue; + } + used_first_nums.insert(nums[i]); + + set seen; + for (int j = i + 1; j < nums.size(); j++) { + int complement = -nums[i] - nums[j]; + if (!seen.contains(complement)) { + seen.insert(nums[j]); + continue; + } + vector triplet = {nums[i], nums[j], complement}; + sort(triplet.begin(), triplet.end()); + unique_triplets.insert(triplet); + } + } + return vector>(unique_triplets.begin(), unique_triplets.end()); + } +};