题目:

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

参考官方题解

排序+双指针:先给数组nums进行升序排序,两个for循环确定前两个数,然后使用双指针确定后两个数,需要考虑以下几种情况进行剪枝:

  • 在确定第一个数之后,如果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+1];
  • 在确定前两个数之后,如果nums[i] + nums[j] + nums[j+1] + nums[j+2] > target ,说明剩下的两个数,无论取什么值,四个数之和一定会大于taret,因此退出第二层循环;
  • 在确定前两个数之后,如果nums[i] + nums[j] + nums[n-2] + nums[n-1] < target ,说明剩下的两个数,无论取什么值,四个数之和一定会小于taret,因此进入下一轮,枚举nums[j+1];

使用双指针:左右指针分别指向下标 j+1和下标 n-1。每次计算四个数的和sum,并进行如下操作:

如果和 sum == target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数;

如果和sum < target,则将左指针右移一位;

如果和sum > target,则将右指针左移一位。

java代码:

 1 class Solution {
2 public List<List<Integer>> fourSum(int[] nums, int target) {
3 List<List<Integer>> res = new ArrayList<List<Integer>>();
4 int n = nums.length;
5 //如果数组的长度小于4
6 if(n < 4) return res;
7 //对数组进行排序
8 Arrays.sort(nums);
9 //第一个数,只能遍历到倒数第4位
10 for(int i = 0; i < n-3; i++){
11 //:先去掉重复值
12 if(i > 0 && nums[i] == nums[i-1]) continue;
13 //如果邻近的四个数大于target,则退出
14 if((long)nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) break;
15 //如果与最大的三个数相加小于target,则说明nums[i]小了,需要进入新一轮循环
16 if((long)nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target) continue;
17 //确定第二个数
18 for(int j = i+1; j < n-2; j++){
19 //去重
20 if(j > i + 1 && nums[j] == nums[j - 1]) continue;
21 //如果和j邻近的两个数和前两个相加之和大于target,则退出
22 if((long)nums[i] + nums[j] + nums[j+1] + nums[j+2] > target) break;
23 //如果与最大的三个数相加小于target,则说明nums[i]小了,需要进入新一轮循环
24 if((long)nums[i] + nums[j] + nums[n-2] + nums[n-1] < target) continue;
25 //确定了两个数之后,后两个数使用双指针
26 int L = j + 1;
27 int R = n - 1;
28 while(L < R){
29 int sum = nums[i] + nums[j] + nums[L] + nums[R];
30 if(sum == target){
31 res.add(Arrays.asList(nums[i], nums[j], nums[L], nums[R]));
32 //跳过重复数
33 while(L < R && nums[L] == nums[L + 1]) L++;
34 while(L < R && nums[R] == nums[R - 1]) R--;
35 L++;
36 R--;
37 }else if(sum < target){
38 L++;
39 }else{
40 R--;
41 }
42 }
43 }
44 }
45 return res;
46 }
47 }

2023-05-11补充:

代码随想录思路: 参考代码随想录文字讲解  &&  代码随想录视频讲解

细节:

①剪枝优化:如果还是只单纯比较nums[i] > target就剪枝,例如:[-4, -1, 0, 0] target = -5,nums[i] = -4 > t-5,剪枝的话后面就会错过答案所有应该加条件变成:nums[i] > target && nums[i] > 0,因为如果这时nums[i] 已经大于target了,nums[i]大于0,i 后面的数都大于0,越加越大,是不会等于target的这时候剪枝就正好。

②由于多了一层循环,故需要多一次剪枝和去重。

 1 class Solution {
2 public List<List<Integer>> fourSum(int[] nums, int target) {
3 List<List<Integer>> ans = new ArrayList<>();
4 Arrays.sort(nums);
5 if (nums.length < 4) return ans;
6 for (int i = 0; i < nums.length; i++){
7 //剪枝,如果nums[i] > 0, nums[i] > target后面相加会越来越大
8 if (nums[i] > target && nums[i] > 0) break;
9 //第一层去重
10 if (i > 0 && nums[i] == nums[i-1]) continue;
11 for (int k = i + 1; k < nums.length; k++){
12 //第二层剪枝
13 int sum1 = nums[i] + nums[k];
14 if (sum1 > target && sum1 > 0) break;
15 //第二层去重
16 if (k > i+1 && nums[k] == nums[k-1]) continue;
17 //开始运用双指针
18 int left = k + 1, right = nums.length - 1;
19 while (left < right){
20 long sum = nums[i] + nums[k] + nums[left] + nums[right];
21 if (sum > target){
22 right--;
23 }else if (sum < target){
24 left++;
25 }else {
26 ans.add(Arrays.asList(nums[i], nums[k], nums[left], nums[right]));
27 //对left和right去重
28 while (left < right && nums[left] == nums[left + 1]) left++;
29 while (left < right && nums[right] == nums[right - 1]) right--;
30 left++;
31 right--;
32 }
33 }
34 }
35 }
36 return ans;
37 }
38 }

小知识:

List<String> list = Arrays.asList("a","b","c"):将数组转换成List集合

注意:

(1)该方法适用于对象型数据的数组(String、Integer...);

(2)该方法不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean);

(3)该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新;

(4)不支持add()、remove()、clear()等方法。

力扣18(java)-四数之和(中等)的更多相关文章

  1. 力扣 ——4Sum (四数之和)python 实现

    题目描述: 中文: 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 targe ...

  2. 【LeetCode】18. 4Sum 四数之和

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:four sum, 4sum, 四数之和,题解,leet ...

  3. Leetcode(18)-四数之和

    给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满 ...

  4. 【LeetCode】18、四数之和

    题目等级:4Sum(Medium) 题目描述: Given an array nums of n integers and an integer target, are there elements ...

  5. 【力扣】454. 四数相加 II

    给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0. 为了使问题简单化,所有的 A ...

  6. [LeetCode] 18. 4Sum 四数之和

    Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...

  7. [leetcode]18. 4Sum四数之和

    Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums s ...

  8. 【LeetCode 18】四数之和

    题目链接 [题解] 两重循环枚举[i..j]这个区间 同时规定必取nums[i]和nums[j] 那么现在的问题就变成在下标为[i..j]这个区间的数字里面找两个数字使他们的和为target-nums ...

  9. [LeetCode] 454. 4Sum II 四数之和II

    Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such t ...

  10. 【LeetCode】 454、四数之和 II

    题目等级:4Sum II(Medium) 题目描述: Given four lists A, B, C, D of integer values, compute how many tuples (i ...

随机推荐

  1. 线上机器 swap 过高导致告警

    哈喽大家好,我是咸鱼. 今天收到了一个告警,说有台服务器上的 swap 过高,已经用了 50% 以上了. 登录机器查看一下内存以及 swap 的使用情况. [root@localhost ~]# fr ...

  2. stm32 串口DMA调试总结和反思

    一 引言 最近在调试stm32的多串口.没想到居然遇到那么多的问题.这里做一个总结,还是非常有必要的. 二 问题 这里先弄清楚几个问题. 1 串口有必要使用DMA吗? DMA可以在串口高速的时候不占用 ...

  3. 3DCAT实时渲染云在虚拟展会中的应用

    随着互联网技术的不断发展,实时3D可视化技术在日常生活中应用越来越广泛,越来越多的行业开始转向线上.今年受新冠肺炎疫情影响很多展会都无法在线下举办,而3d线上虚拟展会采用了全新的在线展示产品方式,将展 ...

  4. Commons-Collections1反序列化

    JDK版本为jdk8u65 commons-collections版本为3.2.1 InvokerTransformer CC1的漏洞点在InvokerTransformer,InvokerTrans ...

  5. multisim中常见的显示器

    multisim中常见的显示器 1.实验原理 multisim中做实验仿真一般需要各种各样的仿真器来模拟实验结果.这里列举几种比较常见的显示器以便后面快速选择. 2.实验操作 (1)LED[二极管] ...

  6. AABO:自适应Anchor设置优化,性能榨取的最后一步 | ECCV 2020 Spotlight

    论文提出超参数优化方法AABO,该方法核心基于贝叶斯优化和Sub-Sample方法,能够自适应的搜索最优的anchor设置.从实验结果来看,AABO能够仅通过anchor设置优化,为SOTA目标检测方 ...

  7. KingbaseES 的角色和权限管理

    KingbaseES使用角色的概念管理数据库访问权限.为了方便权限管理,用户可以建立多个角色,对角色进行授权和权限回收,并把角色授予其他用户. 数据库初始化时,会创建一个超级用户的角色:system( ...

  8. linux xfce 在文件管理器里点击运行shell脚本文件

    1.打开 Settings Editor 2.点击左边的 thunar 3.点击右边的 添加 ,在属性中输入 /misc-exec-shell-scripts-by-default 在类型中选择布尔类 ...

  9. 我们正在被 DDoS 攻击,但是我们啥也不干,随便攻击...

    最近,一场激烈的攻防大战在网络世界悄然上演. 主角不是什么国家安全局或者黑客组织,而是一家名不见经传的创业公司--TablePlus. DDoS 攻击者们摩拳擦掌,跃跃欲试.他们从四面八方蜂拥而至,誓 ...

  10. C语言跨平台时间操作计算时间差

    头文件 #pragma once #if defined(_WIN32) #include<sys/timeb.h> #if defined(__UNIX__)||defined(__AP ...