title: 3Sum slug: three-sum difficulty: medium leetcode_id: 15 leetcode_url: https://leetcode.com/problems/3sum/ categories: - arrays - two-pointers - sorting patterns: - two-pointers description: | Given an integer array `nums`, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0. Notice that the solution set must not contain duplicate triplets. constraints: | - 3 <= nums.length <= 3000 - -10^5 <= nums[i] <= 10^5 examples: - input: "nums = [-1,0,1,2,-1,-4]" output: "[[-1,-1,2],[-1,0,1]]" explanation: "The distinct triplets that sum to zero." - input: "nums = [0,1,1]" output: "[]" explanation: "No triplet sums to zero." - input: "nums = [0,0,0]" output: "[[0,0,0]]" explanation: "Only one triplet sums to zero." explanation: approach: | 1. Sort the array 2. For each element nums[i], find pairs that sum to -nums[i] 3. Use two pointers (left, right) to find pairs in the remaining array 4. Skip duplicates at each level to avoid duplicate triplets intuition: | After sorting, for each fixed element nums[i], we need to find nums[j] + nums[k] = -nums[i]. This reduces to the Two Sum II problem on a sorted array, solvable with two pointers. Sorting enables two things: efficient two-pointer search and easy duplicate skipping. We skip duplicates by checking if current value equals previous value. common_pitfalls: - title: Not handling duplicates description: | Without duplicate skipping, you'll return duplicate triplets. Skip at the outer loop and both pointers. wrong_approach: "Not skipping when nums[i] == nums[i-1]" correct_approach: "if i > 0 and nums[i] == nums[i-1]: continue" - title: Wrong pointer skipping description: | After finding a valid triplet, skip duplicates for both left and right pointers while maintaining left < right. - title: Starting i too late description: | The outer loop should start at index 0. Also, skip if nums[i] > 0 since sorted array means no valid triplet possible. key_takeaways: - Reduce N-sum to (N-1)-sum by fixing one element - Sorting enables two-pointer approach and duplicate handling - Duplicate skipping happens at multiple levels - Time complexity is O(n²) — can't do better for returning all triplets time_complexity: "O(n²)" space_complexity: "O(log n) to O(n)" complexity_explanation: | Time: O(n log n) for sorting + O(n²) for the two-pointer search. Space: Depends on sorting algorithm (log n for in-place, n for non-in-place). solutions: - approach_name: Sort + Two Pointers (Optimal) is_optimal: true code: | def three_sum(nums: list[int]) -> list[list[int]]: nums.sort() result = [] for i in range(len(nums) - 2): # Skip duplicates for i if i > 0 and nums[i] == nums[i - 1]: continue # Early termination if nums[i] > 0: break left, right = i + 1, len(nums) - 1 while left < right: total = nums[i] + nums[left] + nums[right] if total < 0: left += 1 elif total > 0: right -= 1 else: result.append([nums[i], nums[left], nums[right]]) # Skip duplicates for left and right while left < right and nums[left] == nums[left + 1]: left += 1 while left < right and nums[right] == nums[right - 1]: right -= 1 left += 1 right -= 1 return result explanation: | Fix one element and use two pointers to find the other two. Skip duplicates at all levels to avoid duplicate triplets.