题目:

给你一个由 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)
链接:https://leetcode.cn/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

参考官方题解

排序+双指针:先给数组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 }

 小知识:

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()等方法。

原文地址:http://www.cnblogs.com/liu-myu/p/16797054.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性