# LC 15. 3Sum ### [Problem link](https://leetcode.com/problems/3sum/) ###### tags: `leedcode` `medium` `python` `c++` `Two Pointer` Given an integer array nums, return all the triplets <code>[nums[i], nums[j], nums[k]]</code> such that <code>i != j</code>, <code>i != k</code>, and <code>j != k</code>, and <code>nums[i] + nums[j] + nums[k] == 0</code>. Notice that the solution set must not contain duplicate triplets. **Example 1:** ``` Input: nums = [-1,0,1,2,-1,-4] Output: [[-1,-1,2],[-1,0,1]] Explanation: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0. nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0. nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0. The distinct triplets are [-1,0,1] and [-1,-1,2]. Notice that the order of the output and the order of the triplets does not matter. ``` **Example 2:** ``` Input: nums = [0,1,1] Output: [] Explanation: The only possible triplet does not sum up to 0. ``` **Example 3:** ``` Input: nums = [0,0,0] Output: [[0,0,0]] Explanation: The only possible triplet sums up to 0. ``` **Constraints:** - <code>3 <= nums.length <= 3000</code> - <code>-10<sup>5</sup> <= nums[i] <= 10<sup>5</sup></code> ## Solution 1 - Two Pointer #### Python ```python= class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: if len(nums) < 3: return [] nums, res = sorted(nums), [] for i in range(len(nums)-2): cur, left, right = nums[i], i + 1, len(nums) - 1 if res != [] and res[-1][0] == cur: continue while left < right: if cur + nums[left] + nums[right] == 0: res.append([cur, nums[left], nums[right]]) while left < right - 1 and nums[left] == nums[left + 1]: left += 1 while left + 1 < right and nums[right] == nums[right - 1]: right -= 1 if cur + nums[left] + nums[right] > 0: right -= 1 else: left += 1 return res ``` #### C++ ```cpp= class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(), nums.end()); int n = nums.size(); vector<vector<int>> res; for (int i = 0; i < n - 2; i++) { if (i > 0 && nums[i - 1] == nums[i]) { continue; } if (nums[i] + nums[i + 1] + nums[i + 2] > 0) { break; } if (nums[i] + nums[n - 2] + nums[n - 1] < 0) { continue; } int j = i + 1; int k = n - 1; while (j < k) { int sum = nums[i] + nums[j] + nums[k]; if (sum < 0) { j++; } else if (sum > 0) { k--; } else { res.push_back({nums[i], nums[j], nums[k]}); j++; while (j < k && nums[j - 1] == nums[j]) { j++; } k--; while (j < k && nums[k] == nums[k + 1]) { k--; } } } } return res; } }; ``` >### Complexity >n = nums.length >| | Time Complexity | Space Complexity | >| ----------- | --------------- | ---------------- | >| Solution 1 | O($n^2$) | O(1) | ## Note sol1: 大致思路如下圖: [ref](https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.md) ![](https://hackmd.io/_uploads/rk9oOAqk6.gif) 代碼隨想錄的code寫複雜了, 應該可以更簡潔的. `--------------------------------------------------------` ```cpp= while (left < right - 1 and nums[left] == nums[left + 1]) { left++; } while (left < right - 1 and nums[right] == nums[right - 1]) { right--; } res.push_back({nums[cur], nums[left++], nums[right--]}); ``` 這裡不能寫成 ```cpp= res.push_back({nums[cur], nums[left++], nums[right--]}); while (left < right - 1 and nums[left] == nums[left + 1]) { left++; } while (left < right - 1 and nums[right] == nums[right - 1]) { right--; } ``` 因為要先找出左右重複的區塊再將結果加到res中, 不然會error, 是一個要注意的小地方 ![](https://hackmd.io/_uploads/HyWmiR5Jp.png) 另外這次發現了一個新的寫法: ```cpp= res.push_back({nums[cur], nums[left++], nums[right--]}); 我通常習慣寫成 res.push_back(vector<int>{nums[cur], nums[left++], nums[right--]}); ``` 這是chatGPT的解釋: ![](https://hackmd.io/_uploads/rJOOF0ck6.png) 挺酷的, 可以學起來. c++: [Ref(video)](https://www.bilibili.com/video/BV1bP411c7oJ/?spm_id_from=333.788&vd_source=088937f16fb413336c0cb260ed86a1c3)