编号18: 四数之和
编号18: 四数之和
题意:给定一个包含 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] ]
思路
四数之和,和三数之和是一个思路,都是使用双指针法, 基本解法就是在三数之和 的基础上再套一层for循环。
但是有一些细节需要注意,例如:不要判断nums[k] > target 就返回了,三数之和 可以通过 nums[i] > 0 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。(大家亲自写代码就能感受出来)
三数之和的双指针解法是一层for循环num[i]为确定值,然后循环内有left和right下表作为双指针,找到nums[i] + nums[left] + nums[right] == 0。
四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下表作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况,三数之和的时间复杂度是O(n2),四数之和的时间复杂度是O(n3) 。
那么一样的道理,五数之和、六数之和等等都采用这种解法。
对于三数之和双指针法就是将原本暴力O(n3)的解法,降为O(n2)的解法,四数之和的双指针解法就是将原本暴力O(n4)的解法,降为O(n3)的解法。
之前我们讲过哈希表的经典题目:四数相加II,相对于本题简单很多,因为本题是要求在一个集合中找出四个数相加等于target,同时四元组不能重复。
而四数相加II是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于本题还是简单了不少!
大家解决一下这两道题目就能感受出来难度的差异。
代码
//双指针求解四数之和
public static List<List<Integer>> FourSum(int[] arr, int target) {
List<List<Integer>> result = new ArrayList<>();
for (int k = 0; k < arr.length; k++) {
// 去重
if (k > 0 && arr[k] == arr[k - 1]) {
continue;
}
for (int i = k + 1; i < arr.length; i++) {
// 正确去重方法
if (i > k + 1 && arr[i] == arr[i - 1]) {
continue;
}
int left = i + 1;
int right = arr.length - 1;
while (right > left) {
if (arr[k] + arr[i] + arr[left] + arr[right] > target) {
right--;
} else if (arr[k] + arr[i] + arr[left] + arr[right] < target) {
left++;
} else {
List<Integer> list = new ArrayList<>();
list.add(arr[i]);
list.add(arr[k]);
list.add(arr[left]);
list.add(arr[right]);
result.add(list);
// 去重逻辑应该放在找到一个四元组之后
while (right > left && arr[right] == arr[right - 1]) right--;
while (right > left && arr[left] == arr[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
}
return result;
}

浙公网安备 33010602011771号