难度中等
给定一个包含 n 个整数的数组 nums
和一个目标值 target
,判断 nums
中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + 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 = [], target = 0 输出:[]
提示:
0 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
解法
和之前的三数之和的解法相似 用在四数之和上,先排序 再 i从0到length 循环, j从i+1到length循环, k和m一头一尾,在j+1到length的区域内k++,m-- 直到碰头。(如果i和j有和之前的一个元素相同的,直接跳过)但是这么写下来时间会很长, 需要剪枝:
以i开始的前四位相加是最小的,所以如果它比target还大。那本次i循环break
以i开始的i的值和数组最后三个数字相加 是本次循环中最大的,如果它小于target 就i++ (即continue)
同理i,j ,j+1,j+2>target 那么j这次循环break
i,j,length-1.length-2<targrt j++;
除此之外要注意当发现相同结果时的处理,在这里是k和m也判断和上一次是否相同,相同就跳过,当有结果时 k++,(m--也一样,避免死循环)官方题解中的方法是,当发现相同的后,左右指针一直移动到和结果不同的数字那里再执行下一次循环,我觉得我的方法好一点、
剪枝的语句先后顺序也有点影响总的用时,但是我现在不想考虑这个。
class Solution {
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ans = new ArrayList<>();
int length = nums.length;
if (length < 4) {
return ans;
}
Arrays.sort(nums);
for (int i = 0; i < length-3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if (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] == nums[j - 1]) {
continue;
}
if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if (nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int k = j + 1;
int m = length - 1;
while (k < m) {
int sum = nums[i] + nums[j]+ nums[k] + nums[m];
if ((m < length - 1 && nums[m] == nums[m + 1]) || sum>target) {
m--;
} else if ((k > j + 1 && nums[k] == nums[k - 1]) || sum<target) {
k++;
} else {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
list.add(nums[m]);
ans.add(list);
k++;
}
}
}
}
return ans;
}
}