LeetCode第18题思悟——四数之和(4sum)
知识点预告
- 数组排序预处理:无序变有序;
- 去重操作的位置选择:去掉冗余代码;
- 遍历前的预判断处理:快速筛选处理;
题目要求
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的思路
此题和leetcode第15题、leetcode第16题属于同类型的题目,所以处理手段和知识点也是大同小异;
核心手段就是先排序,然后双重循环,遍历第1、2个数,然后通过双指针遍历寻找第3,4个数,然后需要注意去重处理;
public List<List<Integer>> fourSum(int[] nums, int target){
List<List<Integer>> result=new ArrayList<>();
if(nums.length<4){
return result;
}
Arrays.sort(nums);
int firstBorder=nums.length-3;
int secondBorder=nums.length-2;
int firstNum;
int secondNum;
int currentSum;
int leftPointer,rightPointer,thirdNum,fourthNum;
List<Integer> answer;
for(int i=0;i<firstBorder;i++){
firstNum=nums[i];
for(int j=i+1;j<secondBorder;j++){
secondNum=nums[j];
leftPointer=j+1;
rightPointer=nums.length-1;
while(leftPointer<rightPointer){
thirdNum=nums[leftPointer];
fourthNum=nums[rightPointer];
currentSum=firstNum+secondNum+thirdNum+fourthNum;
if(currentSum<target){
leftPointer++;
while(leftPointer<rightPointer&&nums[leftPointer]==thirdNum){
leftPointer++;
}
}else if(currentSum>target){
rightPointer--;
while(leftPointer<rightPointer&&nums[rightPointer]==fourthNum){
rightPointer--;
}
}else{
answer=new ArrayList<>();
answer.add(firstNum);
answer.add(secondNum);
answer.add(thirdNum);
answer.add(fourthNum);
result.add(answer);
while(leftPointer<rightPointer&&nums[leftPointer]==thirdNum){
leftPointer++;
}
while(leftPointer<rightPointer&&nums[rightPointer]==fourthNum){
rightPointer--;
}
}
}
while(j<secondBorder&&nums[j]==secondNum){
j++;
}
j--;
}
while(i<firstBorder&&nums[i]==firstNum){
i++;
}
i--;
}
return result;
}
优秀解法
//解法A
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new LinkedList<>();
Arrays.sort(nums);
int n = nums.length;
for (int i = 0; i < n - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
if (nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target) continue;
for (int j = i + 1; j < n - 2; j++) {
if (j - i > 1 && nums[j] == nums[j - 1]) continue;
if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
if (nums[i] + nums[j] + nums[n - 1] + nums[n - 2] < target) continue;
int left = j + 1;
int right = n - 1;
while (left < right) {
int tmp = nums[i] + nums[j] + nums[left] + nums[right];
if (tmp == target) {
List<Integer> tmpList = new LinkedList<>(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
res.add(tmpList);
while (left < right && nums[left] == nums[left + 1]) left += 1;
while (left < right && nums[right] == nums[right - 1]) right -= 1;
left += 1;
right -= 1;
} else if (tmp > target) right -= 1;
else left += 1;
}
}
}
return res;
}
差异分析
从当前提交情况来看,该题主流解法有两种,一种是我的思路一节中提到的解法,另一种就是优秀解法啦;而后者比前者运行情况更好一点;
除了共有的排序、双指针遍历等技巧外有些解法还有以下几个亮点:
- 去重位置的选择:这一点同第15题、第16题的分析,自己的解法中对于去重的处理显得很冗余;
- 前置条件的判断:可以快速筛选掉一些值,提高处理效率;算是遍历前的预处理;
知识点小结
- 数组排序预处理;
- 去重操作的位置选择;
- 遍历前的预判断处理;