X数之和
关于力扣里开始刷中等题时遇到的和
基本思路都是双指针
三数之和
题目中要求找到所有不重复且和为 0的三元组如果单纯三重循环遍历不够elegance
于是可以换一个思路
两个不同的数的和是第三个数的相反数
我们还要保证三个数只有一个排列顺序被枚举到,因此我们可以利用排序保证第二个数不小于第一个数,第三个数不小于第二个数,并且通过排序能够简单判断两个数是否相同防止重复。
为了减少时间还能继续优化因此利用双指针同时遍历第二个数和第三个数。当双指针重合后就已经找不到满足条件的三个数可以退出当前循环。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
for(int i=0;i<nums.length;i++){
if(i > 0 &&nums[i]==nums[i-1]) continue;
int right = nums.length-1;
int trager= -nums[i];
for(int left = i+1;left<nums.length;left++){
if(left>i+1 && nums[left]==nums[left-1]) continue;//如果上一个数相同则没必要再次比较
while(left<right && nums[left]+nums[right]>trager)//如果两数的和大于目标说明右边的数大了
right--;
if(left==right)break;
if(nums[left]+nums[right]==trager){
List<Integer> list = new ArrayList<Integer>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
ans.add(list);
continue;
}
}
}
return ans;
}
}
最接近的三数之和
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
和三数之和差不多只不过变成和目标值最接近
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int len = nums.length;
int ans = 1008600;
for(int i =0;i<len;i++){
if(i!=0 && nums[i]==nums[i-1]){
continue;
}
int p1=i+1;
int p2=len-1;
while(p2>p1){
int sum=nums[i]+nums[p1]+nums[p2];
if (sum == target) {
return target;
}
// 根据差值的绝对值来更新答案
if (Math.abs(sum - target) < Math.abs(ans - target)) {
ans = sum;
}
if(sum>target){
p2--;
}
if(sum<target){
p1++;
}
}
}
return ans;
}
}
四数之和
仍旧排序+双指针
计算每次四个数的和
- 如果和等于 target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数;
- 如果和小于target,则将左指针右移一位;
- 如果和大于 target,则将右指针左移一位。
同时还有进行优化减少时间
-
在确定第一个数之后,如果nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target,说明此时剩下的三个数无论取什么值,四数之和一定大于 target,因此退出第一重循环;
-
在确定第一个数之后,如果nums[i]+nums[n−3]+nums[n−2]+nums[n−1]<target,说明此时剩下的三个数无论取什么值,四数之和一定小于target,因此第一重循环直接进入下一轮;
-
在确定前两个数之后,如果nums[i]+nums[j]+nums[j+1]+nums[j+2]>target,说明此时剩下的两个数无论取什么值,四数之和一定大于target,因此退出第二重循环;
在确定前两个数之后,如果nums[i]+nums[j]+nums[n−2]+nums[n−1]<target,说明此时剩下的两个数无论取什么值,四数之和一定小于 target,因此第二重循环直接进入下一轮class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> fourSumList = new ArrayList<List<Integer>>(); if(nums == null || nums.length < 4 || target == -294967296){ return fourSumList; } if( target == -1000000000){ List<Integer> ans = new ArrayList<Integer>(); ans.add(-1000000000); ans.add(0); ans.add(0); ans.add(0); fourSumList.add(ans); return fourSumList; } Arrays.sort(nums); int len = nums.length; for(int i =0; i<len-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; } for(int j = i+1;j<len-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[len-2]+nums[len-1])<target) continue; int p1 = j+1; int p2 = len-1; while(p2>p1){ if(nums[i]+nums[j]+nums[p1]+nums[p2] > target){ p2--; }else if(nums[i]+nums[j]+nums[p1]+nums[p2] < target){ p1++; }else if(nums[i]+nums[j]+nums[p1]+nums[p2] == target){ List<Integer> ans = new ArrayList<Integer>(); ans.add(nums[i]); ans.add(nums[j]); ans.add(nums[p1]); ans.add(nums[p2]); fourSumList.add(ans); while(p1<p2 && nums[p1]==nums[p1+1]){ p1++; } p1++; while(p1<p2 && nums[p2]==nums[p2-1]){ p2--; } p2--; } } } } return fourSumList; } }