任务说明如下:https://codility.com/demo/take-sample-test/peaks 它也在这里:Codility Peaks Complexity
首先,我尝试自己解决这个问题,但只能想出我认为是蛮力的解决方案。但是,它得分为100/100:https://codility.com/demo/results/demoRNWC3P-X4U
这显然对我来说完全不满意。 ;)为每个因子N
(或每个峰值,以较小者为准)调用外部循环,并为每个峰调用内部循环(仅检查每个块中是否存在峰值)。也许那是O(N^2)
,也许好一点(因为它在时间限制内通过了测试),但我几乎可以肯定它不是O(N*log(log(N)))
。
然后我尝试搜索O(N*log(log(N)))
解决方案,但其他所有人似乎都有与我相似的解决方案。
那么有人对O(N*log(log(N)))
(或更好的)解决方案有所了解吗?
此外,如果有人能告诉我我的解决方案有多复杂,我将不胜感激。
答案 0 :(得分:2)
你的代码是O(n d(n)),其中d(n)是n的除数。在[1,100000]上,d(n)在83160 = 2 ^ 3 3 ^ 3 5 7 11处最大化,其具有126个除数。 According to Wikipedia,对于每个epsilon> 0,d(n)为o(n ^ epsilon),因此它的增长相当缓慢。
要获得O(n log log n)解,请构建一个部分和数组,告诉您每个点剩余多少个峰。然后你可以判断O(1)时间内是否存在一个峰值。检查除数d然后需要O(n / d)时间。在所有除数d上加n / d与在所有除数d上加d相同,结果是,根据相同的维基百科页面,O(n log log n)。
答案 1 :(得分:0)
我已经实现了tmyklebu建议的解决方案(谢谢!),它应该是n.log(log(n))。 Codility不再测试'表现'关于这个问题(!)但是python解决方案的准确性得分为100%。
顺便说一句,如果您正在进行Codility课程,您将从Lesson 8: Prime and composite numbers记住,谐波数操作的总和会给出O(log(n))复杂度。我们有一个减少的集合,因为我们只关注因子分母。 Lesson 9: Sieve of Eratosthenes显示素数的倒数之和如何为O(log(log(n)))并声称证明是非平凡的'。除数倒数的总和与素数倒数的总和不同,但我认为它属于“非平凡”的倒数。证明类别!
def solution(data):
length = len(data)
# array ends can't be peaks, len < 3 must return 0
if len < 3:
return 0
peaks = [0] * length
# compute a list of 'peaks to the left' in O(n) time
for index in range(2, length):
peaks[index] = peaks[index - 1]
# check if there was a peak to the left, add it to the count
if data[index - 1] > data[index - 2] and data[index - 1] > data[index]:
peaks[index] += 1
# candidate is the block size we're going to test
for candidate in range(3, length + 1):
# skip if not a factor
if length % candidate != 0:
continue
# test at each point n / block
valid = True
index = candidate
while index != length:
# if no peak in this block, break
if peaks[index] == peaks[index - candidate]:
valid = False
break
index += candidate
# one additional check since peaks[length] is outside of array
if index == length and peaks[index - 1] == peaks[index - candidate]:
valid = False
if valid:
return length / candidate
return 0