Codility's Peaks的O(N * log(log(N)))算法?

时间:2014-10-01 20:38:04

标签: algorithm prime-factoring

任务说明如下: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))) (或更好的)解决方案有所了解吗?

此外,如果有人能告诉我我的解决方案有多复杂,我将不胜感激。

2 个答案:

答案 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