diff --git a/15_3sum/memo.md b/15_3sum/memo.md new file mode 100644 index 0000000..ae03f53 --- /dev/null +++ b/15_3sum/memo.md @@ -0,0 +1,28 @@ +# 15. 3Sum + +https://leetcode.com/problems/3sum/ + +## Comments + +### step1 + +* 1 つ固定して two sum するか、sort する方法もありそうだな (一瞬 binary search が頭をよぎった)、などと考える +* `Solution` を書いてみたが、 重複を許さないの考慮していなかった (認識はしていたが、重複排除についてしっかり考えられていなかった) + * two sum 部分を関数に切り出すkと主考えたが、`triplets` を引数で受け渡して書き込めるようにするのか、2 要素の `vector>` を返して `nums[i]` につけるのか、値の返し方で迷ったので一旦関数化はせずに書くことにした。 +* 後で考えると、このコードには重複以外にも問題があって、set を使っているので、出現回数を考慮 (異なるインデックスの値をすべて網羅) していない。 + * e.g. `nums = [0, 0, 0, 0]` のとき、`i = 0` で固定すると、本来は `{0,1,2}, {0,1,3}, {0,2,3}` (index) の 3 つが見つかってほしいけど、`{0, 1, 2}, {0, 1, 3}` しか追加されない +* 重複排除なら sort するか、と思ったが 12 分くらい経っていたので step2 へ。 + +### step2 + +* 一応 sort してやれば `step1.Solution` のアプローチのままでも重複排除は可能 + * `Solution1` +* ただ、どうせ sort するなら two pointer 的なアプローチのほうが良さそう -> `Solution2` +* TODO: 一応 sort せずに解く方法もありそうだが、時間がなさそうなので今回はスキップ。 + * 探査して結果を set に入れるようなことをすればよさそうではある + * https://leetcode.com/problems/3sum/submissions/1882175465/ + + +### step3 + +* skip diff --git a/15_3sum/step1.cpp b/15_3sum/step1.cpp new file mode 100644 index 0000000..f8ec10d --- /dev/null +++ b/15_3sum/step1.cpp @@ -0,0 +1,18 @@ +class Solution { +public: + vector> threeSum(vector& nums) { + vector> triplets; + for (int i = 0; i < nums.size(); ++i) { + int target_num = -nums[i]; // nums[i] - 0 + std::unordered_set seen; + for (int j = i + 1; j < nums.size(); ++j) { + int complement = target_num - nums[j]; + if (seen.contains(complement)) { + triplets.push_back({nums[i], nums[j], complement}); + } + seen.insert(nums[j]); + } + } + return triplets; + } +}; diff --git a/15_3sum/step2.cpp b/15_3sum/step2.cpp new file mode 100644 index 0000000..d26827e --- /dev/null +++ b/15_3sum/step2.cpp @@ -0,0 +1,64 @@ +// sort + hashset +#include + +class Solution { +public: + vector> threeSum(vector& nums) { + std::sort(nums.begin(), nums.end()); + vector> triplets; + for (int i = 0; i < nums.size(); ++i) { + if (i > 0 && nums[i] == nums[i - 1]) continue; + + int target_num =-nums[i]; // nums[i] - 0 + std::unordered_set seen; + for (int j = i + 1; j < nums.size(); ++j) { + int complement = target_num - nums[j]; + if (seen.contains(complement)) { + triplets.push_back({nums[i], nums[j], complement}); + while (j + 1 < nums.size() && nums[j] == nums[j + 1]) { + ++j; + } + } + seen.insert(nums[j]); + } + } + return triplets; + } +}; + +// sort + two pointers +#include + +class Solution2 { +public: + vector> threeSum(vector& nums) { + vector> result; + std::sort(nums.begin(), nums.end()); + for (int i = 0; i < nums.size(); ++i) { + // To avoid duplicates (skip the same number) + if (i > 0 && nums[i - 1] == nums[i]) continue; + + int left = i + 1; + int right = nums.size() - 1; + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + if (sum < 0) { + ++left; + continue; + } + if (sum > 0) { + --right; + continue; + } + // sum == 0 + result.push_back({nums[i], nums[left], nums[right]}); + + while (left < right && nums[left] == nums[left + 1]) ++left; + while (left < right && nums[right - 1] == nums[right]) --right; + ++left; + --right; + } + } + return result; + } +}; diff --git a/15_3sum/step3.cpp b/15_3sum/step3.cpp new file mode 100644 index 0000000..e69de29