The 3Sum With Multiplicity problem asks you to determine the number of triplets (i, j, k)
in an array arr
such that i < j < k
and arr[i] + arr[j] + arr[k] == target
. Unlike the classic 3Sum problem, elements in arr
can have duplicates, and each valid combination of indices counts as a separate triplet. The answer should be returned modulo 10^9 + 7
to avoid large numbers.
arr
(with possible duplicate values) and an integer target
.(i, j, k)
such that i < j < k
and arr[i] + arr[j] + arr[k] == target
.At first glance, the problem seems similar to the classic 3Sum, but with a twist: we care about the number of index-based combinations, not just unique values, and duplicates in the array matter. A brute-force approach would involve three nested loops to check every possible triplet, but this would be too slow for large arrays.
To optimize, we can notice that:
x
, y
, z
(where x ≤ y ≤ z
), and checking if x + y + z == target
, we can calculate the number of valid index combinations for each case.We solve the problem efficiently using a frequency array and combinatorics. Here’s the step-by-step plan:
count
where count[x]
is the number of times x
appears in arr
.
x
from 0 to 100, y
from x
to 100, and z
from y
to 100:
x + y + z == target
.x
, y
, and z
:x == y == z
): Use count[x] choose 3
.x == y != z
or x != y == z
): Use count[x] choose 2 * count[z]
or count[x] * count[y] choose 2
.count[x] * count[y] * count[z]
.10^9 + 7
.
We use a frequency array (hash map or fixed-size array) because the range of numbers is small, making lookups and combinations efficient. The combinatorics formulae are:
C(n, 2) = n * (n - 1) / 2
C(n, 3) = n * (n - 1) * (n - 2) / 6
Input: arr = [1,1,2,2,3,3,4,4,5,5]
, target = 8
x ≤ y ≤ z
with x + y + z = 8
:
1 + 2 + 5 = 8
: All different, so total = 2*2*2 = 81 + 3 + 4 = 8
: All different, so total = 2*2*2 = 82 + 2 + 4 = 8
: 2's are same, so total = C(2,2)*2 = 1*2 = 22 + 3 + 3 = 8
: 3's are same, so total = 2*C(2,2) = 2*1 = 2The answer is 20 triplets.
arr
.We solved the 3Sum With Multiplicity problem by leveraging the small range of possible values to count frequencies and use combinatorics, instead of brute-force enumeration. This approach is both efficient and elegant, using mathematical combinations to count valid index triplets. The key insight is to reduce the problem to counting value triplets and calculating the number of valid index combinations for each, making full use of the problem’s constraints.
class Solution:
def threeSumMulti(self, arr, target):
MOD = 10 ** 9 + 7
count = [0] * 101
for num in arr:
count[num] += 1
ans = 0
for x in range(101):
if count[x] == 0:
continue
for y in range(x, 101):
if count[y] == 0:
continue
z = target - x - y
if z < y or z > 100 or count[z] == 0:
continue
if x == y == z:
ans += count[x] * (count[x] - 1) * (count[x] - 2) // 6
elif x == y != z:
ans += count[x] * (count[x] - 1) // 2 * count[z]
elif x < y and y == z:
ans += count[x] * count[y] * (count[y] - 1) // 2
elif x < y < z:
ans += count[x] * count[y] * count[z]
ans %= MOD
return ans
class Solution {
public:
int threeSumMulti(vector<int>& arr, int target) {
const int MOD = 1e9 + 7;
vector<long long> count(101, 0);
for (int num : arr) count[num]++;
long long ans = 0;
for (int x = 0; x <= 100; ++x) {
if (count[x] == 0) continue;
for (int y = x; y <= 100; ++y) {
if (count[y] == 0) continue;
int z = target - x - y;
if (z < y || z > 100 || count[z] == 0) continue;
if (x == y && y == z) {
ans += count[x] * (count[x] - 1) * (count[x] - 2) / 6;
} else if (x == y && y != z) {
ans += count[x] * (count[x] - 1) / 2 * count[z];
} else if (x < y && y == z) {
ans += count[x] * count[y] * (count[y] - 1) / 2;
} else if (x < y && y < z) {
ans += count[x] * count[y] * count[z];
}
ans %= MOD;
}
}
return (int)ans;
}
};
class Solution {
public int threeSumMulti(int[] arr, int target) {
int MOD = 1_000_000_007;
long[] count = new long[101];
for (int num : arr) count[num]++;
long ans = 0;
for (int x = 0; x <= 100; x++) {
if (count[x] == 0) continue;
for (int y = x; y <= 100; y++) {
if (count[y] == 0) continue;
int z = target - x - y;
if (z < y || z > 100 || count[z] == 0) continue;
if (x == y && y == z) {
ans += count[x] * (count[x] - 1) * (count[x] - 2) / 6;
} else if (x == y && y != z) {
ans += count[x] * (count[x] - 1) / 2 * count[z];
} else if (x < y && y == z) {
ans += count[x] * count[y] * (count[y] - 1) / 2;
} else if (x < y && y < z) {
ans += count[x] * count[y] * count[z];
}
ans %= MOD;
}
}
return (int)ans;
}
}
var threeSumMulti = function(arr, target) {
const MOD = 1e9 + 7;
let count = new Array(101).fill(0);
for (let num of arr) count[num]++;
let ans = 0;
for (let x = 0; x <= 100; x++) {
if (count[x] === 0) continue;
for (let y = x; y <= 100; y++) {
if (count[y] === 0) continue;
let z = target - x - y;
if (z < y || z > 100 || count[z] === 0) continue;
if (x === y && y === z) {
ans += count[x] * (count[x] - 1) * (count[x] - 2) / 6;
} else if (x === y && y !== z) {
ans += count[x] * (count[x] - 1) / 2 * count[z];
} else if (x < y && y === z) {
ans += count[x] * count[y] * (count[y] - 1) / 2;
} else if (x < y && y < z) {
ans += count[x] * count[y] * count[z];
}
ans %= MOD;
}
}
return ans;
};