Medium
题目描述
给你一个歌曲列表,其中第 i 首歌曲的持续时间为 time[i] 秒。
返回其总持续时间(以秒为单位)可被 60 整除的歌曲对的数量。形式上,我们希望下标数量 i, j 使得 i < j 且 (time[i] + time[j]) % 60 == 0。
示例 1:
输入:time = [30,20,150,100,40]
输出:3
解释:三对歌曲的总持续时间可被 60 整除:
(time[0] = 30, time[2] = 150):总持续时间 180
(time[1] = 20, time[3] = 100):总持续时间 120
(time[1] = 20, time[4] = 40):总持续时间 60
示例 2:
输入:time = [60,60,60]
输出:3
解释:所有三对歌曲的总持续时间都是 120,可以被 60 整除。
提示:
1 <= time.length <= 6 * 10^41 <= time[i] <= 500
解题思路
这道题的关键在于理解模运算的性质。如果两个数的和能被60整除,那么它们对60取模的结果之和也能被60整除。
解题思路:
暴力解法:双重循环遍历所有配对,时间复杂度O(n²),在数据规模较大时会超时。
哈希表优化(推荐):利用余数互补的性质进行优化。对于每个歌曲时长t,我们只关心t % 60的值。如果两个余数r1和r2满足(r1 + r2) % 60 == 0,那么r2 = (60 - r1) % 60。
具体实现步骤:
- 创建一个长度为60的数组count,记录每个余数值出现的次数
- 遍历歌曲列表,对于每首歌曲:
- 计算当前歌曲的余数remainder = time[i] % 60
- 计算需要配对的余数target = (60 - remainder) % 60
- 将count[target]加到结果中(这些是之前遍历过的能与当前歌曲配对的歌曲数)
- 将count[remainder]增加1
特殊情况处理:
- 当remainder为0时,target也为0,需要与其他余数为0的歌曲配对
- 当remainder为30时,target也为30,需要与其他余数为30的歌曲配对
这种方法时间复杂度O(n),空间复杂度O(1),是最优解法。
代码实现
class Solution {
public:
int numPairsDivisibleBy60(vector<int>& time) {
vector<int> count(60, 0);
int result = 0;
for (int t : time) {
int remainder = t % 60;
int target = (60 - remainder) % 60;
result += count[target];
count[remainder]++;
}
return result;
}
};
class Solution:
def numPairsDivisibleBy60(self, time: List[int]) -> int:
count = [0] * 60
result = 0
for t in time:
remainder = t % 60
target = (60 - remainder) % 60
result += count[target]
count[remainder] += 1
return result
public class Solution {
public int NumPairsDivisibleBy60(int[] time) {
int[] count = new int[60];
int result = 0;
foreach (int t in time) {
int remainder = t % 60;
int target = (60 - remainder) % 60;
result += count[target];
count[remainder]++;
}
return result;
}
}
/**
* @param {number[]} time
* @return {number}
*/
var numPairsDivisibleBy60 = function(time) {
const count = new Array(60).fill(0);
let result = 0;
for (const t of time) {
const remainder = t % 60;
const target = (60 - remainder) % 60;
result += count[target];
count[remainder]++;
}
return result;
};
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 遍历一次数组,每次操作为O(1) |
| 空间复杂度 | O(1) | 使用固定大小60的数组存储计数 |
相关题目
. Destroy Sequential Targets (Medium)