LeetCode 2198 - Number of Single Divisor Triplets
The problem asks us to count how many ordered triplets of distinct indices (i, j, k) satisfy a very specific divisibility condition.
Difficulty: 🟡 Medium
Topics: Array, Counting, Enumeration
Solution
Problem Understanding
The problem asks us to count how many ordered triplets of distinct indices (i, j, k) satisfy a very specific divisibility condition.
For every triplet, we compute:
$$\text{sum} = nums[i] + nums[j] + nums[k]$$
The triplet is considered valid if this sum is divisible by exactly one of the three participating values:
nums[i]nums[j]nums[k]
The indices must all be distinct, meaning we cannot reuse the same array position multiple times, even if values are equal.
An important detail is that the problem counts ordered triplets, not unordered combinations. This means (0,1,2) and (2,1,0) are considered different triplets. If a value combination works, every valid permutation of the corresponding indices contributes separately to the answer.
The input size is large:
nums.lengthcan be up to10^5nums[i]is at most100
This constraint is the key observation of the entire problem. Although the array itself is huge, the value range is extremely small. Instead of thinking in terms of indices, we should think in terms of frequencies of values.
Several edge cases are important:
- Arrays with many duplicates, such as
[1,2,2] - Arrays where all values are identical
- Triplets where two or all three values are equal
- Values equal to
1, since every integer is divisible by1 - Large arrays where brute force enumeration is impossible
The bounded value range strongly suggests using counting and frequency-based enumeration instead of iterating over all index triplets.
Approaches
Brute Force Approach
The most direct solution is to try every possible triplet of distinct indices.
For every triple (i, j, k):
- Compute the sum.
- Check whether the sum is divisible by
nums[i]. - Check whether the sum is divisible by
nums[j]. - Check whether the sum is divisible by
nums[k]. - Count how many of these divisibility checks succeed.
- If exactly one succeeds, increment the answer.
This works because it literally follows the definition of the problem.
However, the time complexity is far too large. There are:
$$O(n^3)$$
possible triplets, and n can be 100000. A cubic solution is completely infeasible.
Key Insight
The critical observation is that every number is between 1 and 100.
That means there are only 100 distinct possible values in the entire array.
Instead of iterating over indices, we can iterate over value combinations:
$$(a, b, c)$$
where each value is between 1 and 100.
There are at most:
$$100^3 = 1,000,000$$
value triplets, which is manageable.
For each value triplet:
- Check whether
a + b + cis divisible by exactly one of them. - Compute how many index triplets can produce this value combination using frequency counts.
- Add the appropriate number of permutations.
This transforms an impossible O(n^3) solution into a practical constant-bounded counting solution.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n³) | O(1) | Enumerates every index triplet directly |
| Optimal | O(100³) | O(100) | Uses frequency counting and value enumeration |
Algorithm Walkthrough
Step 1: Count Frequencies
Create a frequency array or hash map storing how many times each value appears.
Since values are only between 1 and 100, a fixed-size array is ideal.
For example:
nums = [1,2,2]
produces:
freq[1] = 1
freq[2] = 2
This allows us to compute how many index selections are possible for any value combination.
Step 2: Enumerate All Value Triplets
Iterate through all possible values:
a from 1 to 100
b from 1 to 100
c from 1 to 100
Skip any value whose frequency is zero.
At this stage we are considering value combinations, not actual indices.
Step 3: Check the Divisibility Condition
Compute:
$$s = a + b + c$$
Now count how many of these are divisors of s:
s % a == 0s % b == 0s % c == 0
If exactly one condition is true, the triplet is valid.
Step 4: Compute How Many Index Triplets Exist
Now determine how many distinct index triplets correspond to (a,b,c).
There are three cases.
Case 1: All Values Distinct
If:
a != b != c
then the number of ordered index triplets is:
$$freq[a] \times freq[b] \times freq[c]$$
because each chosen index is automatically distinct.
Case 2: Two Values Equal
Suppose:
a == b != c
Then we must choose two distinct indices for value a.
The count becomes:
$$freq[a] \times (freq[a]-1) \times freq[c]$$
The same logic applies to the other equality patterns.
Case 3: All Values Equal
If:
a == b == c
we need three distinct indices:
$$freq[a] \times (freq[a]-1) \times (freq[a]-2)$$
Step 5: Add the Count
Add all valid ordered triplet counts into the final answer.
Because we are already iterating over ordered value triplets (a,b,c), permutations are naturally included.
Why it works
The algorithm works because every valid ordered index triplet corresponds to exactly one ordered value triplet (a,b,c).
The divisibility test depends only on the values, not the indices themselves. Therefore we can evaluate validity once per value combination and then multiply by the number of index arrangements that realize that combination.
Since the frequency formulas correctly count distinct index selections for all equality patterns, every valid triplet is counted exactly once.
Python Solution
from typing import List
class Solution:
def singleDivisorTriplet(self, nums: List[int]) -> int:
freq = [0] * 101
for num in nums:
freq[num] += 1
answer = 0
for a in range(1, 101):
if freq[a] == 0:
continue
for b in range(1, 101):
if freq[b] == 0:
continue
for c in range(1, 101):
if freq[c] == 0:
continue
total = a + b + c
divisible_count = 0
if total % a == 0:
divisible_count += 1
if total % b == 0:
divisible_count += 1
if total % c == 0:
divisible_count += 1
if divisible_count != 1:
continue
if a == b == c:
if freq[a] >= 3:
answer += (
freq[a]
* (freq[a] - 1)
* (freq[a] - 2)
)
elif a == b:
if freq[a] >= 2:
answer += (
freq[a]
* (freq[a] - 1)
* freq[c]
)
elif a == c:
if freq[a] >= 2:
answer += (
freq[a]
* (freq[a] - 1)
* freq[b]
)
elif b == c:
if freq[b] >= 2:
answer += (
freq[a]
* freq[b]
* (freq[b] - 1)
)
else:
answer += freq[a] * freq[b] * freq[c]
return answer
The implementation begins by building a frequency array for all possible values from 1 to 100. This converts the problem from index-based enumeration into value-based counting.
The three nested loops enumerate every ordered value triplet (a,b,c). Since the value range is fixed and tiny, this is efficient enough.
For each triplet, the code computes the total sum and counts how many of the three values divide that sum. Only combinations where exactly one divisor condition holds are kept.
The next section determines how many actual index triplets correspond to the current value combination. The implementation carefully handles the three equality cases separately:
- all equal
- exactly two equal
- all distinct
This ensures indices remain distinct while preserving ordered permutations.
Finally, the computed count is added into the running total.
Go Solution
func singleDivisorTriplet(nums []int) int64 {
freq := make([]int64, 101)
for _, num := range nums {
freq[num]++
}
var answer int64 = 0
for a := 1; a <= 100; a++ {
if freq[a] == 0 {
continue
}
for b := 1; b <= 100; b++ {
if freq[b] == 0 {
continue
}
for c := 1; c <= 100; c++ {
if freq[c] == 0 {
continue
}
total := a + b + c
divisibleCount := 0
if total%a == 0 {
divisibleCount++
}
if total%b == 0 {
divisibleCount++
}
if total%c == 0 {
divisibleCount++
}
if divisibleCount != 1 {
continue
}
if a == b && b == c {
if freq[a] >= 3 {
answer += freq[a] *
(freq[a] - 1) *
(freq[a] - 2)
}
} else if a == b {
if freq[a] >= 2 {
answer += freq[a] *
(freq[a] - 1) *
freq[c]
}
} else if a == c {
if freq[a] >= 2 {
answer += freq[a] *
(freq[a] - 1) *
freq[b]
}
} else if b == c {
if freq[b] >= 2 {
answer += freq[a] *
freq[b] *
(freq[b] - 1)
}
} else {
answer += freq[a] * freq[b] * freq[c]
}
}
}
}
return answer
}
The Go version follows the same logic as the Python implementation. One important difference is that the function returns int64, so the frequency array and answer variable also use int64 to avoid overflow during multiplication.
Go arrays and slices are initialized with zero values automatically, which simplifies frequency counting.
Worked Examples
Example 1
nums = [4,6,7,3,2]
Frequency Table
| Value | Frequency |
|---|---|
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 6 | 1 |
| 7 | 1 |
Consider value triplet (4,3,2).
Step 1: Compute Sum
| a | b | c | Sum |
|---|---|---|---|
| 4 | 3 | 2 | 9 |
Step 2: Divisibility Check
| Divisor | Result |
|---|---|
| 9 % 4 | 1 |
| 9 % 3 | 0 |
| 9 % 2 | 1 |
Exactly one divisor works, namely 3.
Step 3: Count Ordered Index Triplets
All values are distinct.
$$1 \times 1 \times 1 = 1$$
But permutations are separately enumerated:
(4,3,2)
(4,2,3)
(3,4,2)
(3,2,4)
(2,4,3)
(2,3,4)
So this contributes 6.
Now consider (4,7,3).
Sum
$$4 + 7 + 3 = 14$$
Divisibility
| Divisor | Result |
|---|---|
| 14 % 4 | 2 |
| 14 % 7 | 0 |
| 14 % 3 | 2 |
Exactly one divisor works again.
This contributes another 6.
Final answer:
6 + 6 = 12
Example 2
nums = [1,2,2]
Frequency Table
| Value | Frequency |
|---|---|
| 1 | 1 |
| 2 | 2 |
Consider (1,2,2).
Sum
$$1 + 2 + 2 = 5$$
Divisibility
| Divisor | Result |
|---|---|
| 5 % 1 | 0 |
| 5 % 2 | 1 |
| 5 % 2 | 1 |
Exactly one divisor works.
Count Index Arrangements
Two values are equal.
$$1 \times 2 \times 1 = 2$$
Accounting for ordered permutations gives:
3! = 6
The algorithm naturally counts all six ordered arrangements during enumeration.
Final answer:
6
Example 3
nums = [1,1,1]
Frequency Table
| Value | Frequency |
|---|---|
| 1 | 3 |
Consider (1,1,1).
Sum
$$1 + 1 + 1 = 3$$
Divisibility
| Divisor | Result |
|---|---|
| 3 % 1 | 0 |
| 3 % 1 | 0 |
| 3 % 1 | 0 |
All three divide the sum.
The condition requires exactly one divisor.
Therefore this triplet is invalid.
Final answer:
0
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(100³) | Enumerates all possible value triplets |
| Space | O(100) | Frequency array for values 1 through 100 |
The algorithm's runtime is effectively constant because the value range is fixed at 100. Even though there are three nested loops, the maximum number of iterations is only one million, which is entirely practical.
The space usage is also constant because the frequency array size never grows with the input length.
Test Cases
sol = Solution()
assert sol.singleDivisorTriplet([4,6,7,3,2]) == 12
# Basic mixed-values example from problem statement
assert sol.singleDivisorTriplet([1,2,2]) == 6
# Duplicate values with valid permutations
assert sol.singleDivisorTriplet([1,1,1]) == 0
# All divisors work, should be invalid
assert sol.singleDivisorTriplet([2,2,2]) == 0
# Sum divisible by all three equal values
assert sol.singleDivisorTriplet([1,1,2]) == 0
# Sum = 4, divisible by both 1s and 2
assert sol.singleDivisorTriplet([2,3,5]) == 6
# Sum = 10, divisible only by 5
assert sol.singleDivisorTriplet([3,4,5]) == 0
# Sum = 12, divisible by both 3 and 4
assert sol.singleDivisorTriplet([1,2,3]) == 0
# Sum = 6, divisible by all three
assert sol.singleDivisorTriplet([7,8,9]) == 6
# Sum = 24, divisible only by 8
assert sol.singleDivisorTriplet([100,100,99]) == 0
# Large values near constraint boundary
assert sol.singleDivisorTriplet([1,2,2,2]) == 18
# Multiple duplicate indices create more permutations
assert sol.singleDivisorTriplet([5,10,15]) == 0
# Sum divisible by all three values
Test Summary
| Test | Why |
|---|---|
[4,6,7,3,2] |
Verifies official example |
[1,2,2] |
Tests duplicate handling |
[1,1,1] |
Ensures exactly-one condition is enforced |
[2,2,2] |
Tests all-equal invalid case |
[1,1,2] |
Tests multiple divisibility matches |
[2,3,5] |
Tests valid distinct triplet |
[3,4,5] |
Tests invalid distinct triplet |
[1,2,3] |
Tests divisibility by all values |
[7,8,9] |
Tests another valid distinct case |
[100,100,99] |
Tests upper value boundary |
[1,2,2,2] |
Tests many duplicate index arrangements |
[5,10,15] |
Tests another fully divisible case |
Edge Cases
All Values Equal
An array like:
[1,1,1]
is a common source of mistakes because every divisor check behaves identically. A naive implementation may accidentally treat this as valid if it only checks whether at least one divisor works. The problem specifically requires exactly one divisor.
The implementation handles this correctly by counting the number of successful divisibility checks and requiring the count to equal exactly 1.
Duplicate Values with Distinct Indices
Arrays such as:
[1,2,2]
require careful handling because equal values can still come from different indices. A common bug is undercounting permutations or failing to enforce distinct indices.
The implementation explicitly uses permutation-style counting formulas:
$$freq[x] \times (freq[x]-1)$$
when two equal values are needed. This guarantees different indices are selected.
Value 1
The value 1 is special because every integer is divisible by 1.
This means any triplet containing multiple 1s can easily violate the "exactly one divisor" rule. For example:
[1,1,2]
produces sum 4, which is divisible by both 1 and 2.
The implementation avoids errors by independently checking divisibility for each position and counting how many succeed, rather than assuming divisibility behavior from the values alone.