📅  最后修改于: 2023-12-03 14:49:27.528000             🧑  作者: Mango
在本文中,我们将介绍如何在一个给定的数组中找到所有满足特定条件的四元组,即它们的和等于 K。
最朴素的解法是使用四个嵌套循环遍历每个可能的组合并计算它们的和。该解法的时间复杂度是 $O(n^4)$,不适用于大型数组。
public static void fourSum(int[] arr, int k) {
int n = arr.length;
for (int i = 0; i < n - 3; i++) {
for (int j = i + 1; j < n - 2; j++) {
for (int p = j + 1; p < n - 1; p++) {
for (int q = p + 1; q < n; q++) {
if (arr[i] + arr[j] + arr[p] + arr[q] == k) {
System.out.println(arr[i] + ", " + arr[j] + ", " + arr[p] + ", " + arr[q]);
}
}
}
}
}
}
我们可以使用哈希表来降低时间复杂度到 $O(n^3)$。具体来说,我们可以使用两重循环枚举前两个数,并记录它们的和,然后使用哈希表查询 K 减去这个和是否在数组中出现了。
public static void fourSum(int[] arr, int k) {
int n = arr.length;
Map<Integer, List<int[]>> pairSums = new HashMap<>();
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
int sum = arr[i] + arr[j];
if (!pairSums.containsKey(sum)) {
pairSums.put(sum, new ArrayList<>());
}
pairSums.get(sum).add(new int[]{i, j});
}
}
Set<List<Integer>> res = new HashSet<>();
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
int target = k - arr[i] - arr[j];
if (pairSums.containsKey(target)) {
for (int[] pair : pairSums.get(target)) {
int x = pair[0];
int y = pair[1];
if (x != i && x != j && y != i && y != j) {
List<Integer> quadruplet = Arrays.asList(arr[i], arr[j], arr[x], arr[y]);
Collections.sort(quadruplet);
res.add(quadruplet);
}
}
}
}
}
for (List<Integer> quadruplet : res) {
System.out.println(quadruplet);
}
}
我们还可以使用排序和双指针技巧来将时间复杂度降至 $O(n^3)$。首先,我们可以对数组进行排序,然后使用两重循环枚举前两个数。对于每一对前两个数,我们可以使用双指针分别指向剩下的数的开头和结尾,将它们的和与 K 减去前两个数的和相比较。如果这个差相等于第二个指针指向的数和第三个指针指向的数之和,我们就找到了一个满足要求的四元组。如果这个差小于第二个指针指向的数和第三个指针指向的数之和,我们可以将第二个指针向右移动一位。如果这个差大于第二个指针指向的数和第三个指针指向的数之和,我们可以将第三个指针向左移动一位。
public static void fourSum(int[] arr, int k) {
int n = arr.length;
Arrays.sort(arr);
Set<List<Integer>> res = new HashSet<>();
for (int i = 0; i < n - 3; i++) {
for (int j = i + 1; j < n - 2; j++) {
int left = j + 1;
int right = n - 1;
while (left < right) {
int sum = arr[i] + arr[j] + arr[left] + arr[right];
if (sum == k) {
res.add(Arrays.asList(arr[i], arr[j], arr[left], arr[right]));
left++;
right--;
} else if (sum < k) {
left++;
} else {
right--;
}
}
}
}
for (List<Integer> quadruplet : res) {
System.out.println(quadruplet);
}
}
在本篇文章中,我们介绍了三种不同的解法来计算给定数组中的和等于 K 的四元组。暴力解法的时间复杂度为 $O(n^4)$,哈希表解法的时间复杂度为 $O(n^3)$,而排序和双指针解法的时间复杂度为 $O(n^3)$。我们建议在实现该算法时使用排序和双指针解法。