python - 使用 python 的 Codility 课程 MaxCounters 是否可能比 O(N+M) 更好?
问题描述
这是我用于 Codility 课程的代码:MaxCounters
def solution(N, A):
counters = [0] * N
max_c = 0
for el in A:
if el >= 1 and el <= N:
counters[el-1] += 1
max_c = max(counters[el-1], max_c)
elif el > N:
counters = [max_c] * N
return counters
每个测试都通过,但最后一个(“所有 max_counter 操作”)在 7 秒后超时,因此结果仅为 88%,时间复杂度为 O(N+M)。
是否可以提高算法的时间复杂度并使用 Python 获得 100% 的测试结果?
MaxCounters 任务
您有 N 个计数器,最初设置为 0,您可以对它们进行两种可能的操作:
- increase(X) - 计数器 X 增加 1,
- max counter - 所有计数器都设置为任何计数器的最大值。
给出了一个由 M 个整数组成的非空数组 A。该数组表示连续操作:
- 如果 A[K] = X,使得 1 ≤ X ≤ N,那么操作 K 是增加(X),
- 如果 A[K] = N + 1 则操作 K 是最大计数器。
为以下假设编写一个有效的算法:
- N 和 M 是 [1..100,000] 范围内的整数;
- 数组 A 的每个元素都是 [1..N + 1] 范围内的整数。
解决方案
编辑:跟进这个答案的评论中的讨论,跟踪最后一个操作以避免在连续的 max_counter 操作中不必要地重置数组是实现目标的关键。以下是实施该更改的不同解决方案(一个跟踪最大值,第二个计算按需最大值)的样子:
def solution(N, A):
counters = [0] * N
max_c = 0
last_was_max = False
for el in A:
if el <= N:
counters[el - 1] += 1
max_c = max(counters[el - 1], max_c)
last_was_max = False
elif not last_was_max:
counters = [max_c] * N
last_was_max = True
return counters
def solution2_1(N, A):
counters = [0] * N
last_was_max = False
for el in A:
if el <= N:
counters[el - 1] += 1
last_was_max = False
elif not last_was_max:
counters = [max(counters)] * N
last_was_max = True
return counters
我不知道提交中使用了哪个实现。
首先,您在 if 条件中浪费了一些时间:无需检查整数是否大于或等于 1,这是练习中给出的。然后,无需评估第二个 elif 语句,只需在那里执行 else 即可。如果不满足第一个条件,则根据练习的定义满足第二个条件
其次,根据我的测试,仅在需要时计算最大值比在所有运行中跟踪它要快得多。这可能是因为 max-operation 只会很少发生,特别是对于 M 的大值,因此您浪费时间多次跟踪内容,而不是在运行期间仅计算几次最大值。
解决@Nearoo 的评论,似乎重新分配数组实际上会改变物理地址,但根据我运行的一些测试,重新分配无论如何都比 for 循环快得多。
def solution2(N, A):
counters = [0] * N
for el in A:
if el <= N:
counters[el - 1] += 1
else:
counters = [max(counters)] * N
return counters
在使用不同种子值的几次测试运行中,我提出的这个解决方案的性能比您的解决方案高出 2-3 倍。这是要重现的代码:
import random
random.seed(101)
N = random.randint(1, 100000)
M = random.randint(1, 100000)
A = [random.randint(1, N + 1) for i in range(M)]
%timeit solution(N,A)
>>> 11.7 ms ± 805 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit solution2(N,A)
>>> 3.63 ms ± 169 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
推荐阅读
- c++ - 与 nana 构建 hello world
- c - E Balaguruswamy 书第 1 章主题子例程第 3 版中的 C 代码错误
- vue.js - 结果Vue GraphQL上缺少电影属性
- python - 使用正则表达式添加前导零
- php - 继续检查数组中的值是否为数组
- mongodb - Morphia - 将单个集合数据映射到多个 pojo
- rest - 有什么方法可以从 Swagger 文件中为我的操作生成 URL?
- python - 将字符串(2018 年 12 月)转换为日期时间
- java - 如何通过反射找到带有特定注释的字段?
- ios - 使用结构在 Swift 5 中使用 JSONDecoder 解析 JSON