昨天是刷题的第 25 天,基本保持了每天一两道,同步分享了其中前 35 题的记录。通过二十多天的摸索,慢慢熟悉 LeetCode 平台,为了提高刷题学习效率,我决定要改变刷题方式:由之前的按顺序做题改为通过标签分类的专项刷题。
可以看到,LeetCode 中对题目会有标签分类,昨天我们恰巧碰到 33-35 题三个连续的二分查找题目,经过整合练习,会有很明显地感觉到通过一系列地练习会更快捷掌握该算法的核心。所以今天起,我们也将按照专题来继续后面的刷题。今天就来数组专题,至于刷的题目,应该会比之前大大增多,看看能刷几道吧。
专题简介
数组是在程序设计中,为了处理方便,把具有相同类型的若干元素按有序的形式组织起来的一种形式。抽象地讲,数组即是有限个类型相同的元素的有序序列。若将此序列命名,那么这个名称即为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素。而用于区分数组的各个元素的数字编号则被称为下标,若为此定义一个变量,即为下标变量。
链接:https://leetcode-cn.com/tag/array/
我们是 Python 来刷题,数组可以对应到 Python 中的列表,有限个类型相同的有序列表,又能够自由变换调整。至于下标,我们通常称为索引。
题目一
第 1010 题:总持续时间可被 60 整除的歌曲
难度: 简单
在歌曲列表中,第 i 首歌曲的持续时间为 time[i] 秒。
返回其总持续时间(以秒为单位)可被 60 整除的歌曲对的数量。形式上,我们希望索引的数字 i 和 j 满足 i < j 且有 (time[i] + time[j]) % 60 == 0。
示例 1:
输入:[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:
输入:[60,60,60]
输出:3
解释:所有三对的总持续时间都是 120,可以被 60 整数。
#来源:力扣(LeetCode)
#链接:https://leetcode-cn.com/problems/pairs-of-songs-with-total-durations-divisible-by-60
题目分析
题目题目中要求是歌曲对,即要对时间列表中的元素两两组合,和被 60 整除便算符合要求的一对。通常首先想到的算法就是循环遍历:
class Solution:
def numPairsDivisibleBy60(self, time: List[int]) -> int:
size = len(time)
count = 0
for i in range(size):
for j in range(i+1,size):
if (time[i]+time[j])%60==0:
count+=1
return count
通过两层 for 循环,找到所有满足题意的组合,简单直接,但一旦提供的时间列表数据繁杂,这解法就会超时:
当数据量巨大时,我们的 for 循环嵌套导致过程太繁琐,导致超时无法通过测试。所以,我们要避开这个循环遍历的思路,重新设计。
思路尝试
回归题意中的要求:和被 60 整除。我们分析满足条件的数字规律,20 + 40 可以,80 + 40 也可以,20 和 80 等效、其相同点是整除 60 后结果是相同的。所以,关键点来了,时间列表中每个数字可能差异极大,但对题目生效的只有该数整除 60 的余数结果:余数为 1 的和余数为 59 的组合必然满足题意要求。
拿到所有余数后,其范围是 0 到 59。假设余数为 1 的有 10 个,余数为 59 的有 5 个,那么我们可以算出它们可以生成 10x5 = 50 对有效结果;但这里特殊的是余数为 0 和 30 的,假设余数为 30 的数字有 10 个,那么产生的不重复有效结果为 10x9/2 = 45 对。
整理一遍思路:先对时间列表中元素每个都整除拿到余数,对每个余数的个数进行一番统计,从统计结果出发,计算可以组合出 60 的结果个数。
代码实现
class Solution:
def