思路:现将给定数组中的元素两两求和,并用Map存储,key是和值,value是求和的两元素值及其下标。然后遍历key集合寻找其中和为0的两个key值,并排除重复元素,即可确定
代码:
public class Solution {
public List<List<Integer>> fourSum(int[] num, int target) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
Map<Integer, List<Integer[]>> sum_list = new HashMap<Integer, List<Integer[]>>(); //用于存放两两元素和,及这两个元素的值和索引
int len = num.length;
Arrays.sort(num);
for(int i=0; i<len-1; i++) {
for(int j=i+1; j<len; j++) {
Integer k = num[i] + num[j];
Integer[] it = new Integer[] {num[i], i, num[j], j};
// 判断此key是否已经存在于sum_list,如果没有,则新建一个List,用于存放元素值及其对应的下标
if(!sum_list.containsKey(k)) {
sum_list.put(k, new ArrayList<Integer[]>());
}
sum_list.get(k).add(it);
}
}
// 取出所有key到一个Set中,遍历Set(Iterator), 然后判断是否存在两个key之和为0的(下面两种取key集合的方式都可以)
Set<Integer> keys = sum_list.keySet();
// Integer[] keys = sum_list.keySet().toArray(new Integer[sum_list.size()]);
for(Integer k: keys) {
if(sum_list.containsKey(target-k)) {
// 分别取出k和target-k对应的List
List<Integer[]> firstList = sum_list.get(k);
List<Integer[]> secondList = sum_list.get(target-k);
// 分别遍历firstList和secondList的列表项,避免相同位置的相同值被重复使用(确保每个值只被用一次)
for(int i=0; i<firstList.size(); i++) {
Integer[] firstItem = firstList.get(i);
for(int j=0; j<secondList.size(); j++) {
Integer[] secondItem = secondList.get(j);
if(firstItem[1]!=secondItem[1] && firstItem[1]!=secondItem[3] && firstItem[3]!=secondItem[1] && firstItem[3]!=secondItem[3]) {
List l = Arrays.asList(firstItem[0], firstItem[2], secondItem[0], secondItem[2]);
Collections.sort(l);
if(!res.contains(l))
res.add(l);
}
}
}
}
}
return res;
}
}