Given an integer array A
, and an integer target
, return the number of tuples i, j, k
such that i < j < k
and A[i] + A[j] + A[k] == target
.
As the answer can be very large, return it modulo 10^9 + 7
.
Example 1:
Input: A = [1,1,2,2,3,3,4,4,5,5], target = 8 Output: 20 Explanation: Enumerating by the values (A[i], A[j], A[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.
Example 2:
Input: A = [1,1,2,2,2,2], target = 5 Output: 12 Explanation: A[i] = 1, A[j] = A[k] = 2 occurs 12 times: We choose one 1 from [1,1] in 2 ways, and two 2s from [2,2,2,2] in 6 ways.
Note:
3 <= A.length <= 3000
0 <= A[i] <= 100
0 <= target <= 300
题目理解:
给定一个数组,从其中找到三个数,使其相加之和为target。同一个数字不能用两次,但是不同位置的相同数字可以一起使用。
解题思路:
从这道题目的约束中规定,数字的个数为3000个,但是数字的种类只有100种,也就是说,数组中存在大量的重复数字。如果去除这些重复数字,那么数组长度为100,使用三重循环可以找到合适的i,j,k,复杂度是N^3。也可以使用两重循环,先对数组进行排序,在确定i和j之后,使用二分法找到k,这样复杂度降低为N^2 logN。
在找到i,j,k之后,在原始数组中查看这些数字是否有重复的,用这些数字的重复次数相乘,就是这种搭配情况出现的次数。
如果i,j,k本身就有重复的数字,那么需要使用排列组合当中的选择运算C,也能计算出当前搭配情况的出现次数。
将所有情况的出现次数相加就是答案
class Solution {
int base = 1000000007;
public int collect(int k, int n){
if(k > n)
return 0;
if(k > n - k)
k = n - k;
long res = 1;
for(int i = 0; i < k; i++) {
res *= n--;
}
for(int i = 0; i < k; i++)
res /= k--;
res %= base;
return (int)res;
}
public int threeSumMulti(int[] A, int target) {
int[] record = new int[101];
int count = 0;
for(int num : A) {
if(record[num] == 0)
count++;
record[num]++;
}
int[] nums = new int[count];
for(int i = 0, j = 0; i < 101; i++){
if(record[i] > 0)
nums[j++] = i;
}
int res = 0;
for(int i = 0; i < count; i++){
for(int j = i; j < count; j++){
int left = j, right = count - 1, k = -1;
int cur = target - nums[i] - nums[j];
while(left <= right){
int mid = left + (right - left) / 2;
if(nums[mid] > cur)
right = mid - 1;
else if(nums[mid] < cur)
left = mid + 1;
else{
k = mid;
break;
}
}
int temp = 0;
if(k != -1){
if(i == j && j == k){
temp = collect(3, record[nums[i]]);
temp %= base;
}
else if(i == j && j != k){
temp = 1;
temp *= collect(2, record[nums[i]]);
temp %= base;
temp *= record[nums[k]];
temp %= base;
}
else if(i != j && j == k){
temp = 1;
temp *= collect(2, record[nums[j]]);
temp %= base;
temp *= record[nums[i]];
temp %= base;
}
else{
temp = 1;
temp *= record[nums[i]];
temp %= base;
temp *= record[nums[j]];
temp %= base;
temp *= record[nums[k]];
temp %= base;
}
//System.out.println(nums[i] + " " + nums[j] + " " + nums[k] + " " + temp);
res += temp;
res %= base;
}
}
}
return res;
}
}