力扣18题解:四数之和
引言
LeetCode上的第18题"四数之和"是一个中等难度的算法题目,要求找出数组中所有和为特定值的四元组。这个问题是"两数之和"和"三数之和"问题的扩展,考察了对哈希表和双指针技巧的运用。本文将通过Java语言实现这一算法,并提供详细分析。
题目描述
给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出所有和为 target
的四元组 (nums[a], nums[b], nums[c], nums[d])
(无序且 a < b < c < d),并返回这些四元组。
问题分析
这个问题可以通过嵌套三重循环来暴力解决,但时间复杂度会非常高(O(n^4))。更高效的方法是使用哈希表来存储元素和它们的索引,然后通过排除一些不可能的组合来减少不必要的计算。
算法设计
- 排序数组:首先对数组进行排序,以便于使用双指针技巧。
- 遍历数组 :遍历数组,对于每个元素
nums[i]
,尝试找到另外三个元素,使得它们的和等于target - nums[i]
。 - 使用哈希表 :对于每个
nums[i]
,使用哈希表来存储(target - 2 * nums[i], i + 1)
的映射,避免重复计算。 - 双指针 :对于每个
nums[i]
,使用双指针技巧在i + 1
到数组末尾的范围内查找和为target - nums[i]
的另外两个数。
Java实现
java
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> list=new ArrayList<>();
Arrays.sort(nums);
for(int k=0;k<nums.length;k++){
if(nums[k]>0&&nums[k]>target&&target>0){
return list;
}
if(k>0&&nums[k]==nums[k-1]){
continue;
}
for(int i=k+1;i<nums.length;i++){
if((nums[i]+nums[k])>0&&(nums[i]+nums[k])>target&&target>0){
return list;
}
if(i>k+1&&nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.length-1;
while(right>left){
long sum=(long)nums[k]+nums[i]+nums[left]+nums[right];
if(sum>target){
right--;
}
else if(sum<target){
left++;
}
else{
list.add(Arrays.asList(nums[k],nums[i],nums[left],nums[right]));
while(right>left&&nums[right]==nums[right-1]) right--;
while(right>left&&nums[left]==nums[left+1]) left++;
right--;
left++;
}
}
}
}
return list;
}
}
注意事项
- 排序数组是为了使用双指针,同时方便跳过重复的元素。
- 在使用双指针时,需要检查
left
和right
索引的前一个元素是否与当前元素相同,以避免重复的四元组。 - 需要检查
i
和j
的索引,避免索引越界。
结语
LeetCode第18题是一个经典的四数之和问题,通过这个问题,我们可以加深对哈希表和双指针技巧的理解。掌握这个问题的解法,对于解决其他类似问题非常有帮助。