1013. Pairs of Songs With Total Durations Divisible by 60
题目
In a list of songs, the i-th song has a duration of time[i] seconds.
Return the number of pairs of songs for which their total duration in seconds is divisible by 60. Formally, we want the number of indices i < j with (time[i] + time[j]) % 60 == 0.
Example 1:
Input: [30,20,150,100,40]
Output: 3
Explanation: Three pairs have a total duration divisible by 60:
(time[0] = 30, time[2] = 150): total duration 180
(time[1] = 20, time[3] = 100): total duration 120
(time[1] = 20, time[4] = 40): total duration 60
错误的代码
使用O(n^2)的时间复杂度:使用i,j的嵌套循环:
虽然结果是正确的但时间超出了限制。
class Solution:
def numPairsDivisibleBy60(self, time: List[int]) -> int:
l=len(time)
cn=0
for i in range(l):
for j in range(i+1,l):
if (time[i]+time[j])%60==0:
cn+=1
return cn
讨论区的代码
class Solution:
def numPairsDivisibleBy60(self, time: List[int]) -> int:
mod = [0] * 61
for t in time:
mod[-1] += mod[(60 - t % 60) % 60]
mod[t % 60] += 1
return mod[-1]
使用61个存储单位存储 60个求余得到的个数,最后一个存储单位存储计数。
注意:(60 - t % 60) % 60 ,其中如果不加外圈的求余 则60对应的是60,而实际应为0。
这样的话,只需要遍历一次,既可以求出结果,时间复杂度为O(n)。
学习一些有效提高效率的方法:
首先是正则表达式的学习:
collection中Counter的方法:
关于collections——容器数据类型
该模块实现了专门的容器数据类型,为Python的通用内置容器、dict、list、set和tuple提供了替代方案。
- namedtuple() 生产函数对于创建元组子类使用命名域
- deque 类列表的容器两端有快速的添加、出栈
- ChainMap 类dict类,用于创建多个映射的单个视图
- Counter dict子类对于计数哈希对象
- OrderedDict dict子类,它记住已添加的订单项
- defaultdict 调用工厂函数来提供缺失值的dict子类
- UserDict 包装字典对象,使dict子类化更容易
- UserList 包装列表对象,以便更容易地进行列表子类化
- UserString 包装字符串对象,以便更容易地进行字符串子类化
暂时先研究一下counter和defaultdict
Counter对象
一个Counter工具被提供为了更方便和快速的计数,举个例子:
>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
... cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> cnt
{3: 3, 4: 3, 5: 3, 6: 3}
>>> cnt={}
>>> for i in li:
cnt[i]+=1
Traceback (most recent call last):
File "<pyshell#13>", line 2, in <module>
cnt[i]+=1
KeyError: 3
>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
最高效的代码
from collections import Counter, defaultdict
class Solution:
def numPairsDivisibleBy60(self, time: List[int]) -> int:
counts = Counter(time)
songs = defaultdict(int)
for i, c in counts.items():
songs[i % 60] += c
targets = dict()
res = 0
for t in songs:
if t in targets:
res += songs[t] * targets[t]
else:
targets[60-t] = songs[t]
for n in (30, 60):
if targets.get(n, 0) > 1:
res += targets[n] * (targets[n]-1) // 2
return res