题目描述
思路解析动画文字版
记住「余数 r 找互补 c=(60−r)%60:先加前面 c 的个数,再把自己 r 记进表」,下面每帧都在套它。
开局计数表是空的。我们从左到右一首一首处理:先拿当前余数去表里找「互补余数」配对,再把当前余数登记进表。
处理第 0 首歌(时长 30)。它对 60 的余数是 30,那么能和它凑成整 60 的「另一半」余数就是 (60 − 30) % 60 = 30。
表里还没有余数为 30 的歌,这首暂时配不上谁,答案不变,仍是 0。
把当前这首的余数 30 记进表(count[30] = 1),后面再来余数为 30 的歌时就能配上它。继续下一首。
处理第 1 首歌(时长 20)。它对 60 的余数是 20,那么能和它凑成整 60 的「另一半」余数就是 (60 − 20) % 60 = 40。
表里还没有余数为 40 的歌,这首暂时配不上谁,答案不变,仍是 0。
把当前这首的余数 20 记进表(count[20] = 1),后面再来余数为 40 的歌时就能配上它。继续下一首。
处理第 2 首歌(时长 150)。它对 60 的余数是 30,那么能和它凑成整 60 的「另一半」余数就是 (60 − 30) % 60 = 30。
表里余数为 30 的歌有 1 首(高亮行),它们各能和当前这首配成一对,答案加 1,累计 1。
把当前这首的余数 30 记进表(count[30] = 2),后面再来余数为 30 的歌时就能配上它。继续下一首。
处理第 3 首歌(时长 100)。它对 60 的余数是 40,那么能和它凑成整 60 的「另一半」余数就是 (60 − 40) % 60 = 20。
表里余数为 20 的歌有 1 首(高亮行),它们各能和当前这首配成一对,答案加 1,累计 2。
把当前这首的余数 40 记进表(count[40] = 1),后面再来余数为 20 的歌时就能配上它。继续下一首。
处理第 4 首歌(时长 40)。它对 60 的余数是 40,那么能和它凑成整 60 的「另一半」余数就是 (60 − 40) % 60 = 20。
表里余数为 20 的歌有 1 首(高亮行),它们各能和当前这首配成一对,答案加 1,累计 3。
把当前这首的余数 40 记进表(count[40] = 2),后面再来余数为 20 的歌时就能配上它。继续下一首。
处理第 5 首歌(时长 60)。它对 60 的余数是 0,那么能和它凑成整 60 的「另一半」余数就是 (60 − 0) % 60 = 0。
表里还没有余数为 0 的歌,这首暂时配不上谁,答案不变,仍是 3。
把当前这首的余数 0 记进表(count[0] = 1),后面再来余数为 0 的歌时就能配上它。继续下一首。
处理第 6 首歌(时长 90)。它对 60 的余数是 30,那么能和它凑成整 60 的「另一半」余数就是 (60 − 30) % 60 = 30。
表里余数为 30 的歌有 2 首(高亮行),它们各能和当前这首配成一对,答案加 2,累计 5。
把当前这首的余数 30 记进表(count[30] = 3),后面再来余数为 30 的歌时就能配上它。继续下一首。
全部 7 首处理完,一共配成 5 对两首之和为 60 整数倍的歌曲。整个过程只扫一遍、只用一张余数计数表。
边界先想清:全 0 余数两两可配、单首为 0、一般情形。
面试重点:认出它就是「两数之和」的余数版。
参考代码
from typing import Listclass Solution: def numPairsDivisibleBy60(self, time: List[int]) -> int: count = [0] * 60 ans = 0 for t in time: r = t % 60 ans += count[(60 - r) % 60] count[r] += 1 return ans复杂度
- 时间:O(n),每首歌只处理一次
- 空间:O(1),计数表固定 60 个余数槽
易错点
面试追问把动画讲成自己的话
追问和「两数之和 LC1」是不是一回事?
追问为什么用长度 60 的数组而不用哈希表?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
制造字母异位词的最小步骤数
LeetCode 1347 · 中等 · 沿着 哈希套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题