18. 四数之和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums,
int target) { // target 可能会负数或正数
vector<vector<int>> result;
sort(nums.begin(), nums.end());

if (nums.size() < 4)
return result; // 不足四个元素

// 优化而已
int size = nums.size();
long begin_prediction =
(long)nums[0] + (long)nums[1] + (long)nums[2] + (long)nums[3];
long end_prediction = (long)nums[size - 1] + (long)nums[size - 2] +
(long)nums[size - 3] + (long)nums[size - 4];
if (target > 0 && begin_prediction > target)
return result;
if (target < 0 && end_prediction < target)
return result;

for (int j = 0; j < size - 3; j++) {
if (j > 0 && nums[j] == nums[j - 1]) { // 去重 j
continue;
}
for (int i = j + 1; i < size - 2; i++) {
if (i > j + 1 && nums[i] == nums[i - 1]) { // 去重 i
continue;
}

int left = i + 1;
int right = size - 1;

while (left < right) {
long sum = (long)nums[j] + (long)nums[i] +
(long)nums[left] + (long)nums[right] -
(long)target;
if (sum > 0) {
right--;
} else if (sum < 0) {
left++;
} else {
result.push_back(
{nums[j], nums[i], nums[left], nums[right]});
while (left < right &&
nums[right] == nums[right - 1]) { // 去重 right
right--;
continue;
}
while (left < right &&
nums[left] == nums[left + 1]) { // 去重 left
left++;
continue;
}
// 缩减,看范围内是否还能继续匹配到
right--;
left++;
}
}
}
}
return result;
}
};

做过三数之和,你才有机会拿下这道题,这里简单看看匹配思路:

image20250118160543959.png

j 从 0 开始遍历,截止到 size - 3,因为后面三个数没有希望组成四数之和。

i 从 j + 1 开始遍历,截止到 size - 2,因为后面两个数没有希望组成三数之和(这是一个降级操作,但是在代码中没有体现出来,而是把它们都放在一起计算 sum 了)。

left = i + 1,right = size - 1。可以看到 i 和 j 在遍历会暂时固定下来,唯有 left 和 right 会持续变化,要去进行匹配的工作。