携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
题目描述
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] + nums[d] == target 你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]] 示例 2:
输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
提示:
- 1 <= nums.length <= 200
- -109 <= nums[i] <= 109
- -109 <= target <= 109
题目元素
给定数组nums,整数target,从数组中找到所有四个位置不同的元素,使他们之和等于target。当两个解答数组中四个元素都相同则视为这两个数组重复,只取一个即可。
解题思路
这道题解题思路和之前的三元素之和相似,都是从数组中取n个元素的和使它等于target,不同的是这里需要取的是四个元素,所以多了一层循环。
这里还多了一个去重的条件条件,需要对获得的四个元素的数组进行去重,要达到去重的目的,首先要确认每一层循环的元素都要比前一层的元素大,并且同一层同一个元素不能多次进行循环。
所以需要先将数组进行排序,排序的目的有两层,一个是方便在循环时进行剪枝操作,另一个是可以在循环时去重。
然后用循环+双指针+剪枝的方式进行求解。
前面两层循环就是遍历第一个元素和第二个元素,双指针就用于确认第三个元素和第四个元素。
首先确定第一个元素位置i和第二个元素位置j,则双指针的左指针位置为j+1,右指针的位置为nums.length-1;
对这四个元素进行累加得到sum,与target的值进行比较;
- 如果sum=target,则将这四个元素放入结果数组,将左指针向右移动(此时与原元素比增大),右指针向左移动(此时与原元素比减小),循环;
- 如果sum>target,此时需要将sum减小,所以要移动右指针(数组是有序的),循环;
- 如果sum<target,此时需要将sum增大,所以要移动左指针(数组是有序的),循环。
循环结束之后则得到解,这里注意整数溢出,需要将累加后的数据转成long。
代码实现
public static List<List<Integer>> fourSum(int[] nums, int target) {
// 进行排序
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int length = nums.length;
for (int i = 0 ; i < length-3; i ++) {
// 第一个元素
// 剪枝操作
if (i > 0 && nums[i-1] == nums[i]) {
continue;
}
if (0L+nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target || 0L+nums[i] + nums[length-3]+ nums[length-2]+ nums[length-1] < target) {
continue;
}
for (int j = i+1; j < length-2;j++) {
if (j > i+1 && nums[j-1] == nums[j]) {
continue;
}
// 剪枝操作
if (0L+nums[i] + nums[j] + nums[j+1] + nums[j+2] > target || 0L+nums[i] + nums[j]+ nums[length-2]+ nums[length-1] < target) {
continue;
}
// 确定第二个元素
// 建立双指针
int left = j + 1;
int right = length -1;
while (left < right) {
long sum = 0L+nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
// 查找到不同的元素
while (left < right && nums[right] == nums[right-1]) {
right--;
}
right--;
while (left < right && nums[left] == nums[left+1]) {
left++;
}
left++;
} else if (sum > target) {
// 查找到不同的元素
while (left < right && nums[right] == nums[right-1]) {
right--;
}
right--;
} else {
// 查找到不同的元素
while (left < right && nums[left] == nums[left+1]) {
left++;
}
left++;
}
}
}
}
return res;
}