Given an integer array arr, and an integer target, return the number of tuples i, j, k such that i < j < k and arr[i] + arr[j] + arr[k] == target.
As the answer can be very large, return it modulo 109 + 7.
Example 1:
Input: arr = [1,1,2,2,3,3,4,4,5,5], target = 8
Output: 20
Explanation:
Enumerating by the values (arr[i], arr[j], arr[k]):
(1, 2, 5) occurs 8 times;
(1, 3, 4) occurs 8 times;
(2, 2, 4) occurs 2 times;
(2, 3, 3) occurs 2 times.
Constraints:
3 <= arr.length <= 3000
0 <= arr[i] <= 100
0 <= target <= 300
在数组arr中找到3个数,使它们的和==target,问有多少组这样的3个数。
思路:
1.HashMap
遍历arr,下标为i,我们要找到target - arr[i],也就是0~i-1范围剩下两个数的和出现了多少次,
然后统计 0~ i-1 下标对应所有数字与arr[ i ]的和出现的次数。这个就是到 i 为止所有两个数的和。
那么到 i+1 时,0~i 范围内所有两个数字和的次数都统计完了,再找target - arr[i+1]出现的次数,加到结果里面。
直到遍历结束。
注意用int型加着加着,在取mod前就会溢出,所以要用long型。
但是这个方法比较慢。
public int threeSumMulti(int[] arr, int target) {
int n = arr.length;
HashMap<Integer, Long> map = new HashMap<>();
long result = 0;
int mod = 1000000007;
for(int i = 0; i < n; i ++) {
result += map.getOrDefault(target - arr[i], 0l);
for(int j = 0; j < i; j++) {
int sum = arr[i] + arr[j];
map.put(sum, map.getOrDefault(sum, 0l) + 1l);
}
}
return (int)(result % mod);
}
2.利用0 <= arr[i] <= 100,
不管数组arr有多长,我就遍历0~100这些数字即可,反正3个元素跑不出这个范围。
但是为了避免出现重复的情况,比如[1, 2, 3]和[2,1,3]和[3,1,2]是同一组3个数字。这中间只取一种来计算,默认取升序排列的。
设3个数字为i, j, k, 取 i <= j <= k这种情况。
这时又分3种情况
1)i == j == k
比如[2, 2, 2], target = 6
2出现了3次,所以次数=3x2x1?然而其实只有一种,所以这种情况要➗6
2)i == j < k
[2, 2, 3], 次数=(2x1)x1?其实仍然是1种,这种情况要➗2
3)i < j < k
用i, j, k三个数字出现的次数相乘即可。
仍然要注意三个数字的次数相乘,在取mod之前就可能溢出,所以要取long型。
public int threeSumMulti(int[] arr, int target) {
long[] cnt = new long[101];
long result = 0;
int mod = 1000000007;
for(int tmp : arr) cnt[tmp] ++;
for(int i = 0; i <= 100; i++) {
for(int j = i; j <= 100; j++) {
int k = target - i - j;
if(k < 0 || k > 100) continue;
if(cnt[i] == 0 || cnt[j] == 0 || cnt[k] == 0) continue;
if(i == j && j == k) {
result += cnt[i] * (cnt[i]-1) * (cnt[i]-2) / 6 ;
} else if(i == j && j != k) {
result += cnt[i] * (cnt[i]-1) / 2 * cnt[k];
} else if(j < k) {
result += cnt[i] * cnt[j] * cnt[k];
}
result %= mod;
}
}
return (int)result % mod;
}