青训营X豆包MarsCode技术训练营|豆包MarsCode AI刷题

46 阅读3分钟

also 中等题 歌曲时长配对问题

问题描述

小F有一个由歌曲组成的列表,每首歌的持续时间用数组 time 表示,其中第 i 首歌的时长为 time[i] 秒。她想知道列表中有多少对歌曲的总持续时间能够被 10 整除。具体来说,我们希望找到所有满足 i < j(time[i] + time[j]) % 10 == 0 的配对。

例如,给定 time = [3, 2, 15, 1, 4],有一对歌曲(time[2]time[4])的时长和为 19 秒,能够被 10 整除。


测试样例

样例1:

输入:time = [3, 2, 15, 1, 4]
输出:0

样例2:

输入:time = [10, 20, 30]
输出:3

样例3:

输入:time = [7, 3, 5, 5, 10]
输出:2

1. 胡乱分析

给定一个列表 time = [t1, t2, ..., tn],我们要找出所有 (i, j) 对使得:

  • i < j
  • (time[i] + time[j]) % 10 == 0

注意到这里并不需要计算每一对歌曲的总时长,而是关注它们的总时长是否能被 10 整除。

2. 余数分类

我们首先可以将所有的歌曲时长对 10 取余,得到每首歌的余数(即 time[i] % 10)。两个时长相加能被 10 整除的条件是它们的余数之和为 10 或 0。具体来说:

  • 如果 time[i] % 10 == r1,那么另一首歌的时长需要满足 time[j] % 10 == (10 - r1) % 10,才能使得 (time[i] + time[j]) % 10 == 0

因此,我们可以用一个数组来记录每个余数的歌曲数量,从而避免暴力枚举所有对。

3. 方案

  1. 遍历 time 数组,对于每首歌的时长,计算其对 10 的余数。
  2. 用一个大小为 10 的计数数组 count 来记录每个余数出现的次数。count[r] 表示余数 r 的歌曲数量。
  3. 对于每个新的时长,我们可以根据其余数来查找能够与之配对的歌曲数量,并更新计数数组。
  4. 处理完所有歌曲后,返回满足条件的配对总数。

4. 具体步骤

  • 初始化一个大小为 10 的计数数组 count,初始值为 0。
  • 遍历每首歌的时长,对其取余,计算可以形成合法对数的数量。
  • 在遍历过程中,更新 count 数组,记录每个余数的歌曲数量。

5. 时间复杂度分析

  • 遍历一次 time 数组,时间复杂度是 O(n),其中 n 是 time 数组的长度。
  • 对每首歌,计算其余数并更新计数数组,因此整体时间复杂度是 O(n)。

案例分析

示例 1

输入:time = [3, 2, 15, 1, 4]

  • 歌曲的余数分别是 [3, 2, 5, 1, 4]
  • 检查所有可能的配对:
    • (3, 2): 3 + 2 = 5, 不能被 10 整除。
    • (3, 5): 3 + 5 = 8, 不能被 10 整除。
    • (3, 1): 3 + 1 = 4, 不能被 10 整除。
    • (3, 4): 3 + 4 = 7, 不能被 10 整除。
    • ...
    • 没有符合条件的配对。
  • 输出:0

示例 2

输入:time = [10, 20, 30]

  • 歌曲的余数分别是 [0, 0, 0]
  • 所有三首歌都可以与其它任何一首歌配对,满足 (time[i] + time[j]) % 10 == 0
    • (10, 20): 10 + 20 = 30, 能被 10 整除。
    • (10, 30): 10 + 30 = 40, 能被 10 整除。
    • (20, 30): 20 + 30 = 50, 能被 10 整除。
  • 输出:3

示例 3

输入:time = [7, 3, 5, 5, 10]

  • 歌曲的余数分别是 [7, 3, 5, 5, 0]
  • 可能的配对:
    • (7, 3): 7 + 3 = 10, 能被 10 整除。
    • (5, 5): 5 + 5 = 10, 能被 10 整除。
  • 输出:2

代码实现

def solution(time):
    # 计数数组,用于存储每个余数的出现次数
    count = [0] * 10
    result = 0

    # 遍历时间列表,计算每个时间的余数
    for t in time:
        remainder = t % 10
        # 寻找与当前余数配对的余数
        complement = (10 - remainder) % 10
        result += count[complement]
        # 更新当前余数的计数
        count[remainder] += 1

    return result