一、题目
给你一个由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
-10<sup>9</sup> <= nums[i] <= 10<sup>9</sup>
-10<sup>9</sup> <= target <= 10<sup>9</sup>
二、题解
仿照三数之和,四重循环肯定不可行,使用循环+双指针的模式,相比三数之和,多一次for循环,a、b两值使用for循环,在出现重复、本循环最小可能数都大于target时,continue;当a循环、某个a循环内的b循环,如果出现最大值小于target时,直接结束for循环,以减少资源消耗。
三、代码
import java.util.*;
public class fourSum_18 {
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(nums == null || nums.length < 4){
return result;
}
Arrays.sort(nums);
for(int i = 0; i < nums.length - 3; i++){ //第一个数
if (i > 0 && nums[i] == nums[i - 1]) { //与前一个相同,跳过该数
continue;
}
if((long) nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target){ //后面的都会超过目标数,跳出循环
break;
}
if((long) nums[i] + nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3] < target){ //本索引开头的数构成的最大组合小于目标数,直接进行下一次循环
continue;
}
for(int j = i + 1; j < nums.length - 2; j++){ //第二个数
if (j > i + 1 && nums[j] == nums[j - 1]) { //与前一个相同,跳过该数
continue;
}
if((long)nums[i] + nums[j] + nums[j+1] + nums[j+2] > target){ //后面的都会超过目标数,跳出循环
break;
}
if((long)nums[i] + nums[j] + nums[nums.length-1] + nums[nums.length-2] < target){ //本索引开头的数构成的最大组合小于目标数,直接进行下一次循环
continue;
}
// 双指针 第三、第四个数
int c = j + 1, d = nums.length - 1;
while(c < d){
long sum = nums[i] + nums[j] + nums[c] + nums[d];
if(sum == target) {
result.add(Arrays.asList(nums[i], nums[j], nums[c], nums[d]));
// c ,d 与 相邻相同
while (c < d && nums[c] == nums[c + 1]) {
c++;
}
c++;
while (c < d && nums[d] == nums[d - 1]) {
d--;
}
d--;
}else if(sum < target){
c++;
}else{
d--;
}
}
}
}
return result;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String[] num = sc.nextLine().split(",");
int nums[] = new int[num.length];
for(int i = 0; i < num.length; i++){
nums[i] = Integer.valueOf(num[i]);
}
Scanner n = new Scanner(System.in);
int target = sc.nextInt();
System.out.println(fourSum(nums,target));
}
}
四、结果
五、总结
- 四个数相加可能会出现超出int表示范围的情况
- 避免临近相同,而判断的语句应当写明大于初始指针所在位置,不然出现重复,如:
2,2,2,2,2
8
对应的唯一结果[[2,2,2,2]]
也会因为消重错误没有结果输出。如下语句,笔者通过前写的是j>i
,该用例未通过。
if (j > i + 1 && nums[j] == nums[j - 1]) { //与前一个相同,跳过该数
continue;
}
六、说明
本文章仅用于记录个人做题记录
由于本人是个小菜鸡(实锤),题目解法并非最优,且解题过程中参考(抄袭)各大佬解题方法,望见谅。