Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
- Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
- The solution set must not contain duplicate quadruplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0. A solution set is: (-1, 0, 0, 1) (-2, -1, 1, 2) (-2, 0, 0, 2)
思路1:
与之前的[leetcode]3Sum类似,加一层外部循环,时间复杂度为O(n ^ 3)
代码如下:
1 public class Solution { 2 public List<List<Integer>> fourSum(int[] num, int target) { 3 List<List<Integer>> result = new ArrayList<List<Integer>>(); 4 if(num == null || num.length < 4) return result; 5 int length = num.length; 6 Arrays.sort(num); 7 for (int i = 0; i < length - 3; i++) { 8 if(i > 0 && num[i] == num[i - 1])continue; 9 int one = i; 10 for (int j = i + 1; j < length - 2; j++) { 11 if(j > i + 1 && num[j] == num[j - 1])continue; 12 int two = j; 13 int three = j + 1; 14 int four = length - 1; 15 while (three < four) { 16 int sum = num[one] + num[two] + num[three] + num[four]; 17 if(sum < target) three++; 18 else if(sum > target) four--; 19 else{ 20 List<Integer> list = new ArrayList<Integer>(); 21 list.add(num[one]); 22 list.add(num[two]); 23 list.add(num[three]); 24 list.add(num[four]); 25 result.add(list); 26 three++; 27 four--; 28 while(three < four && num[three] == num[three-1]) three++; 29 while(three < four &&num[four] == num[four+1]) four--; 30 } 31 } 32 } 33 } 34 return result; 35 } 36 }
【吐槽】第一次做这道题的时候,怎么也想不到O(n ^ 3)居然能过,绞尽乳汁【(⊙o⊙)好邪恶】想怎么才能把时间复杂度压缩到O(n ^ 2),我相信面试的时候要求肯定也是O(n^2),因此查了网上的一些大神的思路,对本题做了进一步的优化
思路2:
1. 计算出数组中两两元素的和,把这种二度元素成为nodeOfTwo(学过排列组合的话,应该可以想象到这个数有多大,没办法,空间换时间吧)
2. 对每一个nodeOfTwo元素进行遍历,类似于求[leetcode]Two Sum
2.1 如果存在两个nodeOfTwo元素的和为target,即找到了满足条件的四个元素。
2.2 nodeOfTwo的value毫无疑问是一个list
疑问:
1. 如何去除相同元素?对于nodeOfTwo - 3【何为3的元素对组合】中可能包含两对或以上(0,3)
2. 如何去除重复元素?对于不同的nodeOfTwo节点的组合,还可能有重复,例如nodeOfTwo - 1 和nodeOfTwo - 4包含一个组合(0,1,1,3)但是nodeOfTwo - 3 和nodeOfTwo - 2 中可能包含(0,3,1,1)事实上是重复元素。
代码如下:
1 public List<List<Integer>> fourSum(int[] num, int target) { 2 List<List<Integer>> result = new ArrayList<List<Integer>>(); 3 if(num == null || num.length < 4) return result; 4 int length = num.length; 5 Arrays.sort(num); 6 Map<Integer,List<int[]>> hash = new HashMap<Integer,List<int[]>>(); 7 for(int i = 0; i < length - 1;i++){ 8 for(int j = i + 1; j < length; j++){ 9 int sum = num[i] + num[j]; 10 if(hash.get(sum) == null){ 11 List<int[]> list = new ArrayList<int[]>(); 12 list.add(new int[]{i,j}); 13 hash.put(sum, list); 14 }else{ 15 hash.get(sum).add(new int[]{i,j}); 16 } 17 } 18 } 19 for(int nodeOfTwo : hash.keySet()){ 20 if(hash.containsKey(target - nodeOfTwo)){ 21 for(int[] oneAndTwo : hash.get(nodeOfTwo)){ 22 for(int[] threeAndFour : hash.get(target - nodeOfTwo)){ 23 if(oneAndTwo[0] == threeAndFour[0] || oneAndTwo[0] == threeAndFour[1] || oneAndTwo[1] == threeAndFour[0] || oneAndTwo[1] == threeAndFour[1] )continue;//去除重复元素 24 int[] node = {num[oneAndTwo[0]],num[oneAndTwo[1]],num[threeAndFour[0]],num[threeAndFour[1]]}; 25 Arrays.sort(node); 26 boolean exist = false; 27 for(List<Integer> tem : result){//去除相同元素 28 int count = 0; 29 for(int i = 0; i < 4; i++){ 30 if(node[i] == tem.get(i))count++; 31 } 32 if(count == 4) exist = true; 33 } 34 if(!exist) { 35 List<Integer> list = new ArrayList<Integer>(); 36 for(int i = 0; i < 4; list.add(node[i++])); 37 result.add(list); 38 } 39 } 40 } 41 } 42 } 43 return result; 44 }
【吐槽】代码还是太丑了,哎,不过与之前的相比还是稍微好点的,慎重点击->[leetcode]4Sum