提示:直接暴力求解会超过执行时间,因此要考虑其他方法降低复杂度。
问题描述
给定一个整数数组 hours,表示时间,以小时为单位。我们需要找到数组中满足 i < j 且 hours[i] + hours[j] 构成整天(即 24 的倍数)的下标对 i 和 j 的数目。整天可以是 1 天(24 小时),2 天(48 小时),以此类推。
一、示例:
示例 1:
输入: hours = [12,12,30,24,24]
输出: 2
解释:构成整天的下标对分别是 (0, 1) 和 (3, 4)。
输入: hours = [72,48,24,3]
输出: 3
解释:构成整天的下标对分别是 (0, 1)、(0, 2) 和 (1, 2)。
二、解题思路
1. 找余数
我们需要找到满足 hours[i] + hours[j] 是 24 的倍数的下标对。首先,观察到对于任意两个数 hours[i] 和 hours[j],如果它们之和是 24 的倍数,那么 hours[i] % 24 + hours[j] % 24 = 24 或者 hours[i] % 24 + hours[j] % 24 = 0。
因此,可以将每个数对 24 取模,得到一个余数,然后我们只需要找到两个余数之和为 24 的数对,或者两个余数都是 0。
2. 利用哈希表存储余数
为了加快查找配对余数的速度,我们可以使用一个大小为 24 的数组 count 来存储余数出现的频率。通过遍历数组 hours,我们可以计算每个元素对 24 的余数,并存储这些余数出现的次数。
当我们处理到某个 hour 时:
如果 hour % 24 == 0,则表示它可以和之前所有余数为 0 的元素配对。
如果 hour % 24 != 0,则需要寻找数组中是否存在 24 - remainder 这样的余数,它们相加就能构成 24 的倍数。
3. 逐步统计配对数
每次找到一对满足条件的余数时,记录它们的配对次数。最终,返回所有配对的总数即可。
代码实现
class Solution(object):
def countCompleteDayPairs(self, hours):
"""
:type hours: List[int]
:rtype: int
"""
count = [0] * 24 # 用一个大小为24的数组存储余数的频率
pairs = 0
for hour in hours:
remainder = hour % 24 # 计算余数
if remainder == 0:
# 余数为0的数可以和之前所有余数为0的数配对
pairs += count[0]
else:
# 查找是否存在能够配对的余数
pairs += count[24 - remainder]
# 更新余数频率
count[remainder] += 1
return pairs
解释代码
1,初始化 count 数组: 我们使用一个大小为 24 的数组 count 来记录每个余数出现的次数。数组索引代表余数,数组的值代表该余数出现的次数。
2,遍历 hours 数组: 对于数组中的每个 hour,我们计算 remainder = hour % 24。
如果余数 remainder == 0,说明这个数可以和之前所有余数为 0 的数配对。于是将 count[0] 加入 pairs 中。如果 remainder != 0,我们需要找是否有 24 - remainder 的余数存在。如果存在,这些余数能够和当前的 hour 配对,所以我们将 count[24 - remainder] 加入 pairs 中。
3,更新频率数组: 无论当前的 remainder 是什么,我们都会将它在 count 数组中的计数加 1,表示这个余数的出现次数。
复杂度分析
时间复杂度: O(n),因为我们只需遍历一次数组,每个元素的余数计算和查找都是 O(1) 操作。
空间复杂度: O(1),因为我们使用了一个固定大小为 24 的数组 count,不依赖于输入数据的大小。
相比使用哈希表存储余数频率,这里我们直接使用数组,因为余数范围固定为 0 到 23,所以数组能够在 O(1) 时间内完成查找和更新,进一步提高了效率。