四数之和与前面三数之和的思路几乎是一样的,嗝。(刚好前些天才写了三数之和的题解)
如果前面的三数之和会做了的话,这里其实就是在前面的基础上多添加一个遍历的指针而已。会做三数之和的可以不用看下面的了。
使用四个指针(a<b<c<d)。固定最小的a和b在左边,c=b+1,d=_size-1 移动两个指针包夹求解。保存使得nums[a]+nums[b]+nums[c]+nums[d]==target的解。偏大时d左移,偏小时c右移。c和d相遇时,表示以当前的a和b为最小值的解已经全部求得。b++,进入下一轮循环b循环,当b循环结束后, a++,进入下一轮a循环。 即(a在最外层循环,里面嵌套b循环,再嵌套双指针c,d包夹求解)。
链接:https://leetcode-cn.com/problems/4sum/solution/shuang-zhi-zhen-jie-fa-can-zhao-san-shu-zhi-he-ge-/
相当于在三数之和的基础上多加了一层遍历循环
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> q = new ArrayList<List<Integer>>();
int len = nums.length;
if (nums == null || len < 4) return q;
// 排序
Arrays.sort(nums);
for (int i = 0; i < len - 3; i++) {
// 去重
if (i > 0 && nums[i] == nums[i - 1]) continue;
// 如果这四数之和大于target, 往后算也必大于target
if ((long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
// 下面这四数之和小于target, 则nums[i]小了
if ((long)nums[i] + nums[len - 3] + nums[len - 2] + nums[len -1] < target) continue;
for (int j = i + 1; j < len - 2; j++) {
// 去重
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
// 如果这四数之和大于target, 往后算也必大于target
if ((long)nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
// 如果这四数之和大于target, 往后算也必大于target
if ((long)nums[i] + nums[j] + nums[len - 2] + nums[len - 1] < target) continue;
// 接下来就是熟悉的双指针算法啦
int L = j + 1;
int R = len - 1;
while (L < R) {
int sum = nums[i] + nums[j] + nums[L] + nums[R];
if (sum == target) {
q.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 q;
}
}
第二天重新做了一遍,细节还是做不到位,下方代码。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
Arrays.sort(nums);
int len = nums.length;
//遍历到还有倒数第四个数结束。
for (int i = 0; i < len - 3; i ++) {
// 去重,在第二次遍历开始后判断是否和前一个数相等,相等就跳过这个位置。
if (i > 0 && nums[i] == nums[i - 1]) continue;
// 如果这四数之和大于target, 终止,因为往后算也必大于target。
if ((long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
// 下面这四数之和小于target, 则nums[i]小了,跳过
if ((long)nums[i] + nums[len - 3] + nums[len - 2] + nums[len -1] < target)
continue;
for (int j = i + 1; j < len - 2; j ++) {
// 去重,同上的去重
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
// 如果这四数之和大于target, 往后算也必大于target,同上
if ((long)nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
// 如果这四数之和大于target, 往后算也必大于target,同上
if ((long)nums[i] + nums[j] + nums[len - 2] + nums[len - 1] < target)
continue;
int l = j + 1;
int r = len - 1;
while (l < r) {
if (nums[i] + nums[j] + nums[l] + nums[r] == target) {
res.add(Arrays.asList(nums[i], nums[j], nums[l], nums[r]));
//去重,用while判断不用if,防止有多个重复。
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
//这用else if 和else,刚开始我用的两个if判断,会少情况
}else if (nums[i] + nums[j] + nums[l] + nums[r] > target) {
r --;
}else {
l ++;
}
}
}
}
return res;
}
}