1. Problem Summary
You are given an integer array time, where each element represents the duration of a song in seconds.
Your task is to determine how many pairs (i, j) exist such that:
i < j (time[i] + time[j]) % 60 == 0
Important details:
- Each pair counts only once
- Order of songs doesn’t matter except i < j constraint
- Durations may vary from small to large values
Example:
Input: [30,20,150,100,40] Valid pairs: (30,150) → 180 % 60 = 0 (20,40) → 60 % 60 = 0 (20,100) → 120 % 60 = 0 Output: 3
2. Key Insights
Insight 1: Modulo remainder drives the condition
Instead of checking sums, we examine:
remainder = time[i] % 60
Insight 2: Complement remainder rule
For a pair to sum to a multiple of 60, we need:
remainderA + remainderB == 60
Special cases:
- remainder = 0 pairs with remainder = 0
- remainder = 30 pairs with remainder = 30
Insight 3: Count frequency of remainders
There are only 60 possible remainders (0–59).
Insight 4: Pair counting via combinations
For normal remainders:
pairs += count[r] * count[60 - r]
For special remainders (0 and 30):
pairs += count[r] * (count[r] - 1) / 2
Insight 5: We only need counts, not explicit pair listings
3. Approach
Count remainders and compute valid combinations
Steps:
- Create array
remainderCount[60] - For each duration, compute
r = time[i] % 60and increment remainder count - Initialize totalPairs = 0
- Add:
- combinations of remainder 0 with itself
- combinations of remainder 30 with itself
- For r from 1 to 29:
- add count[r] * count[60 – r] to totalPairs
- Return totalPairs
4. Time and Space Complexity
Time Complexity:
O(N)
Single pass through input and fixed remainder loop.
Space Complexity:
O(1)
Remainder array always size 60.
5. Java Solution
class Solution {
public int numPairsDivisibleBy60(int[] time) {
int[] remainderCount = new int[60];
for (int t : time) {
remainderCount[t % 60]++;
}
int pairs = 0;
pairs += remainderCount[0] * (remainderCount[0] - 1) / 2;
pairs += remainderCount[30] * (remainderCount[30] - 1) / 2;
for (int r = 1; r < 30; r++) {
pairs += remainderCount[r] * remainderCount[60 - r];
}
return pairs;
}
}
6. Dry Run Examples
Example 1
Input:
[30,20,150,100,40]
Remainders:
30,20,30,40,40
Counts:
count[20]=1 count[30]=2 count[40]=2
Pairs:
30 with 30 → 1 20 with 40 → 2 pairs Total = 3
Output:
3
Example 2
Input:
[60,60,60]
Remainders:
0,0,0
count[0] = 3
Pairs = 3C2 = 3
Output:
3
Example 3
Input:
[10,50,90,30]
Remainders:
10,50,30,30
Pairs:
10 + 50 → valid
30 + 30 → valid
Output:
2
Example 4
Input:
[1,2,3,4,5]
No valid pairs
Output:
0
Example 5
Input:
[15,45,75,105]
All remainders = 15
But only pairs formed if complement exists
No complement remainder 45? Actually yes:
45 is present → pairs formed:
(15,45), (15,75?), (45,75?) etc compute:
Remainders:
15,45,15,45
Pairs:
15 pairs with 45:
2 * 2 = 4
Output:
4
7. Why This Solution Works
- Converts problem into modular arithmetic
- Uses complement pairing technique
- Avoids O(N²) brute force
- Constant memory footprint
- Handles large inputs efficiently
8. Common Mistakes
- Forgetting special cases: remainder 0 and 30
- Double-counting pairs
- Using nested loops (too slow)
- Incorrect modulo for negative numbers (not applicable here)
- Including i == j pairs (not allowed)
