题目描述:
Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.
To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1.
Example:
Input:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
Output:
2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
相比4Sum这道题简单了不少,一开始看错了题目要求,以为要把所有组合都找出来,这样倒是比原题麻烦一点儿,但思路还算简单:
如果是暴力强解,复杂度应该是O(n^4),但咱们可以把A,B和C,D两两组合起来,再去找答案,这样就降低成了O(n^2)
先将A+B的所有组合,保存到一个map里,key是两者的sum,value是index的组合。 C+D一样操作。
再遍历A+B的map的key值,去找C+D的map的key值中有没有 A+B key值的相反数,有的话保存组合到list里。
代码如下:
public List<List<Integer>>fourSumII(int[]A,int[]B,int[]C,int[]D){
List<List<Integer>>L=new ArrayList<List<Integer>>();
List<Integer>l;
HashMap<Integer,HashSet<int[]>>map1=new HashMap<Integer,HashSet<int[]>>(),map2=new HashMap<Integer,HashSet<int[]>>();
HashSet<int[]>set;
int[]temp;
int sum;
for(int i=0;i<A.length;i++){
for(int j=0;j<B.length;j++){
sum=A[i]+B[j];
if(map1.containsKey(sum)){
set=map1.get(sum);
}
else
set=new HashSet<int[]>();
temp=new int[2];
temp[0]=i;
temp[1]=j;
set.add(temp);
map1.put(sum, set);
}
}
for(int i=0;i<C.length;i++){
for(int j=0;j<D.length;j++){
sum=C[i]+D[j];
if(map2.containsKey(sum)){
set=map2.get(sum);
}
else
set=new HashSet<int[]>();
temp=new int[2];
temp[0]=i;
temp[1]=j;
set.add(temp);
map2.put(sum, set);
}
}
HashSet<int[]>rest;
for(int sum1:map1.keySet()){
if(!map2.containsKey(-sum1))continue;
rest=map2.get(-sum1);
for(int[]h1:map1.get(sum1)){
for(int[]h2:rest){
l=new ArrayList<Integer>();
for(int i:h1)l.add(i);
for(int i:h2)l.add(i);
L.add(l);
}
}
}
return L;
}
题目的真实要求是找出组合的数目,这样就稍微简单一点了,
A+B,C+D的操作类似上述,但value值保存的是key值对应的个数。
再去遍历,总和等于A+Bmap的key值个数乘以C+Dmap中-key对应的个数。
代码如下:
public int fourSumII2(int[]A,int[]B,int[]C,int[]D){
HashMap<Integer,Integer>m1=new HashMap<Integer,Integer>();
HashMap<Integer,Integer>m2=new HashMap<Integer,Integer>();
int sum=0,times;
for(int i=0;i<A.length;i++){
for(int j=0;j<B.length;j++){
sum=A[i]+B[j];
if(m1.containsKey(sum)){
times=m1.get(sum);
times++;
m1.put(sum, times);
}
else
m1.put(sum, 1);
}
}
for(int i=0;i<C.length;i++){
for(int j=0;j<D.length;j++){
sum=C[i]+D[j];
if(m2.containsKey(sum)){
times=m2.get(sum);
times++;
m2.put(sum, times);
}
else
m2.put(sum, 1);
}
}
int total=0;
for(int p1:m1.keySet()){
if(m2.containsKey(-p1)){
total+=m1.get(p1)*m2.get(-p1);
}
}
return total;
}