题目描述:
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[[-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2]]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
四数之和其实和三数之和的思路差不多,定义一个外循环,循环遍历排列后的数组除了最后3个的其他元素,循环体里面就是一个三数之和了,区别在于sum是四个元素的相加。另外,还可以考虑每一层的循环中能达到的最小最大值,和target做比较,如果该层中的最小最大值分别大于和小于target,那就可以直接跳过这一层了,以此来减少迭代的次数。
代码(Java):
public class Redo {
public static void main(String[] args) {
int[] nums = new int[] {-1,0,1,2,-1,-4};
int target = -1;
System.out.println(fourSum(nums, target));
}
public static List<List<Integer>> fourSum(int[] nums,int target){
List<List<Integer>> ans = new ArrayList<List<Integer>>();
if(nums==null || nums.length<4) return ans;
Arrays.sort(nums);
int length = nums.length;
for(int h = 0;h<length-3;h++) {
if(h>0 && nums[h]==nums[h-1]) continue; //这个数字出现在这一位(第一位)的情况已经有了,跳过
int min1 = nums[h]+nums[h+1]+nums[h+2]+nums[h+3]; //这个是h这个循环中能达到的最小值
if(min1>target) {//如果这个最小值都比target大,那就没有值等于target的了,直接结束
break;
}
int max1 = nums[h]+nums[length-1]+nums[length-2]+nums[length-3]; //这个是h这个循环中能达到的最大值
System.out.println(max1);
if(max1<target) {//如果这个最小值都比target小,那就没有值等于target的了,直接跳过
continue;
}
for(int i = h+1;i<length-2;i++) {
if(i>h+1 && nums[i]==nums[i-1]) continue;//这个数字出现在这一位(第二位)的情况已经有了,跳过
int j = i+1;
int k = length-1;
int min2 = nums[h]+nums[i]+nums[j]+nums[j+1];//这个是i这个循环中能达到的最小值
if(min2>target) {//如果这个最小值都比target大,那就没有值等于target的了,直接跳过
continue;
}
int max2 = nums[h]+nums[i]+nums[k]+nums[k-1];//这个是i这个循环中能达到的最大值
if(max2<target) {//如果这个最小值都比target小,那就没有值等于target的了,直接跳过
continue;
}
while(j<k) {
int sum = nums[h]+nums[i]+nums[j]+nums[k];
if(sum==target) {
ans.add(Arrays.asList(nums[h],nums[i],nums[j],nums[k]));
j++;
while(j<k && nums[j]==nums[j-1]) j++;
k--;
while(j<k && nums[k]==nums[k+1]) k--;
}
else if(sum>target) k--;
else if(sum<target) j++;
}
}
}
return ans;
}