2 POINTERS › TWO POINTER ON ARRAYS
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →A quadruplet is valid when four different positions contribute values whose sum is target, but the order of those positions does not matter. Sorting gives every quadruplet a canonical nondecreasing order. Once the array is sorted, equal values sit together, so choosing the first occurrence of a value at each decision point is enough to represent all value combinations without repeating one.
Fix the first two values, nums[i] and nums[j]. The remaining task is to find two values after j whose sum is target - nums[i] - nums[j]. Because that suffix is sorted, left and right tell you whether the current sum is too small or too large: move left rightward to increase the sum, or move right leftward to decrease it. After finding a pair, move both pointers and skip equal neighbors.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n^3) | Sorting costs O(n log n). The outer index i has O(n) choices, the inner index j has O(n) choices, and each fixed pair performs an O(n) inward scan; the pointers only move inward, so one scan does not revisit an index. The cubic term dominates. |
| Space | O(log n) extra | The answer itself is required output and is excluded. Apart from it, the scan stores only a fixed number of indices and sum variables; std::sort may use O(log n) recursion stack space, so the bound is O(log n) and does not degrade for any arrangement of the input. |
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
int n = nums.size();
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < n; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
int left = j + 1;
int right = n - 1;
while (left < right) {
long long sum = 1LL * nums[i] + nums[j]
+ nums[left] + nums[right];
if (sum == target) {
ans.push_back({nums[i], nums[j], nums[left], nums[right]});
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return ans;
}
};The duplicate checks belong at three different moments. The i check prevents repeating the first value, the j check prevents repeating the second value for the same i, and the two checks after a match prevent repeating either member of the final pair. Skipping only at the outer loops is not enough: repeated left or right values can still append the same quadruplet multiple times.