15题的变式
题意:
给出一个数组和目标和target,在数组中找到四个数,使他们相加之和为target
我的思路: 双层循环(最优解法即为O(N^2^))
51%, O(N^2^)
类似15题,先排序,外层是两层循环,内层是两个指针找剩余两个数的和
步骤:
1. 数组排序
2. 双层遍历数组nums[i]和nums[j],如果i>0且nums[i]不等于nums[i - 1]时,继续二层循环;当==j> i + 1==(表示不是改变i重新循环后的第一个数)且nums[j]不等于nums[j - 1]时,继续下面的操作
3. 设置指针low = j + 1,high = length - 1
3. 当low和high位置的数相加>target- nums[i] - nums[j]时,high–;
4. 当low和high的数相加小于时,low++;
5. 相等时,将目前的组合加入result,并且检测low之后的数,若相同low++跳过,high之前的数,若相同high–跳过
改进:效率提高至82%!!!
==由此可见,涉及到多层循环的,提前判断避免不必要的进入内循环是非常必要的。==
提高效率可以加上几个判断使得非法值一开始就能检测出,避免不必要的循环
- 当nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target或者nums[i]+nums[j]+nums[j+1]+nums[j+2]>target时,证明该趟外层循环最小的和都比target大,跳出;
- nums[i]+nums[nums.length-1]+nums[nums.length-2]+nums[nums.length-3]
改进后的代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res= new ArrayList<>();
int len = nums.length;
if (len < 4) {
return res;
}
Arrays.sort(nums);
for (int i = 0; i < len - 3; i++) {
if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target)continue;
if(nums[i]+nums[nums.length-1]+nums[nums.length-2]+nums[nums.length-3]<target)continue;
if (i > 0 && nums[i - 1] == nums[i]) {
continue;
}
for (int j = i + 1; j < len - 2; j++) {
if(nums[i]+nums[j]+nums[j+1]+nums[j+2]>target)continue; //second candidate too large
if(nums[i]+nums[j]+nums[nums.length-1]+nums[nums.length-2]<target)continue; //second candidate too small
if (j > i + 1 && nums[j - 1] == nums[j]) {
continue;
}
int low = j + 1;
int high = len - 1;
int temp = target - nums[i] - nums[j];
while (low < high) {
int sum = nums[low] + nums[high];
if (sum < temp) {
low++;
}
else if (sum > temp) {
high--;
}
else {
res.add(Arrays.asList(nums[i], nums[j], nums[low], nums[high]));
while (low < high && nums[low + 1] == nums[low]) {
low++;
}
while (low < high && nums[high - 1] == nums[high]) {
high--;
}
low++;
high--;
}
}
}
}
return res;
}
}