问题:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < na、b、c和d互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
解题思路: 四数之和问题可以看做是三数之和问题的扩展,可以采用类似的思路来解决。
首先对数组进行排序,然后枚举前两个数(i 和 j),再使用双指针法找到剩下的两个数(left 和 right),使它们的和为 target。具体步骤如下:
-
对数组 nums 进行排序,方便后续的操作。
-
枚举第一个数 i,遍历范围为 [0, nums.length-3],如果 i>0 且 nums[i] === nums[i-1],则跳过本次循环,避免重复。
-
枚举第二个数 j,遍历范围为 [i+1, nums.length-2],如果 j>i+1 且 nums[j] === nums[j-1],则跳过本次循环,避免重复。
-
定义双指针 left 和 right,分别指向 j+1 和 nums.length-1,当 left<right 时循环:
- 计算四个数的和 sum = nums[i] + nums[j] + nums[left] + nums[right],如果 sum 等于 target,则将这四个数加入到结果数组 res 中,并移动 left 和 right 指针,同时跳过重复的元素。
- 如果 sum 小于 target,则将 left 指针向右移动一位。
- 如果 sum 大于 target,则将 right 指针向左移动一位。
- 返回结果数组 res。
这样的时间复杂度为 O(n^3),空间复杂度为 O(1)。 运行代码:
function fourSum(nums, target) {
let res = [];
if (nums.length < 4) return res;
nums.sort((a, b) => a - b); // 排序
for (let i = 0; i < nums.length - 3; i++) {
if (i > 0 && nums[i] === nums[i - 1]) continue; // 避免重复
for (let j = i + 1; j < nums.length - 2; j++) {
if (j > i + 1 && nums[j] === nums[j - 1]) continue; // 避免重复
let left = j + 1, right = nums.length - 1;
while (left < right) {
let sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum === target) {
res.push([nums[i], nums[j], nums[left], nums[right]]);
while (left < right && nums[left] === nums[left + 1]) left++; // 避免重复
while (left < right && nums[right] === nums[right - 1]) right--; // 避免重复
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return res;
}
当运行上述 JavaScript 代码时,可以按照以下步骤进行思考:
- 输入待求解的数组 nums 和目标值 target。
- 调用 fourSum 函数,传入数组 nums 和目标值 target。
- 在函数内部,首先对输入的数组 nums 进行排序,以便后续的操作。
- 然后使用两层嵌套循环来枚举第一个数和第二个数(i 和 j),并在内部使用双指针法找到剩下的两个数(left 和 right),使它们的和为 target。
- 当找到满足条件的四个数时,将其加入结果数组 res 中。
- 最终返回结果数组 res,即为符合条件的四个数的组合。
在实际运行时,可以针对不同的输入数据进行测试,观察程序的输出结果,以验证代码的正确性。