两数/三数/四数之和
medium双指针哈希表排序
两数之和(LeetCode 1)
哈希表,O(n):
int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int comp = target - nums[i];
if (map.containsKey(comp)) return new int[]{map.get(comp), i};
map.put(nums[i], i);
}
return new int[]{};
}
变体:有序数组两数之和(LeetCode 167) 用左右双指针:
int[] twoSumSorted(int[] numbers, int target) {
int l = 0, r = numbers.length - 1;
while (l < r) {
int sum = numbers[l] + numbers[r];
if (sum == target) return new int[]{l + 1, r + 1};
if (sum < target) l++; else r--;
}
return new int[]{};
}
三数之和(LeetCode 15)
排序后枚举第一个数,内层用双指针:
List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
if (nums[i] > 0) break; // 最小数已正
int l = i + 1, r = nums.length - 1;
while (l < r) {
int sum = nums[i] + nums[l] + nums[r];
if (sum == 0) {
res.add(Arrays.asList(nums[i], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++; // 去重
while (l < r && nums[r] == nums[r - 1]) r--; // 去重
l++; r--;
} else if (sum < 0) l++;
else r--;
}
}
return res;
}
最接近的三数之和(LeetCode 16)
int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int closest = nums[0] + nums[1] + nums[2];
for (int i = 0; i < nums.length - 2; i++) {
int l = i + 1, r = nums.length - 1;
while (l < r) {
int sum = nums[i] + nums[l] + nums[r];
if (Math.abs(sum - target) < Math.abs(closest - target)) closest = sum;
if (sum < target) l++;
else if (sum > target) r--;
else return sum;
}
}
return closest;
}
四数之和(LeetCode 18)
再套一层枚举,双指针不变:
List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < n - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
int l = j + 1, r = n - 1;
while (l < r) {
long sum = (long) nums[i] + nums[j] + nums[l] + nums[r];
if (sum == target) {
res.add(Arrays.asList(nums[i], nums[j], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++; r--;
} else if (sum < target) l++;
else r--;
}
}
}
return res;
}
注意:四数之和可能溢出 int,用 long 计算。
总结
| 题目 | 方法 | 时间 |
|---|---|---|
| 两数之和 | 哈希表 | O(n) |
| 有序数组两数之和 | 双指针 | O(n) |
| 三数之和 | 排序+双指针 | O(n²) |
| 最接近三数之和 | 排序+双指针 | O(n²) |
| 四数之和 | 排序+双指针 | O(n³) |