簡體   English   中英

在找到第 n 個完美冪數時優化運行時間

[英]optimizing runtime on finding the nth perfect power number

我的任務是編寫代碼來找到第 n 個完美的冪數 我寫了以下 function 來找到該數字,但運行時間很長,數字很高(超過 30)。 您可以假設輸入的數字在 1-100 的范圍內。 這是代碼:

def perfect(n: int) -> int:
    """
    :param n: enter the n'th place perfect power num you'd like
    :return: the n'th perfect power number
    """
    powers = []
    i = 1
    for i in range(0, n**2+1):
        for k in range(0, i):
            for m in range(0, i):
                if m ** k == i:
                    powers.append(i)
                    i += 1
                    break
        if len(powers) == n:
            break
    return powers[n-1] 

與許多此類問題一樣,您應該考慮尋找更好的算法,而不是加快您擁有的算法。

在這種情況下,您所做的是遍歷連續整數並測試每個整數是否是完美冪。 您對完美冪的測試可能會得到顯着改進,但有更好的方法:由於完美冪相對稀疏,因此更容易直接生成完美冪。

這很容易做到:我們可以簡單地為n >= 2k >= 2的范圍生成n**k形式的所有數字。 唯一的問題是我們需要完美的權力來維持秩序

以下解決方案的關鍵思想是將完美冪的序列 4、8、9、16、25 4, 8, 9, 16, 25, ...視為多個流的按順序合並:我們首先采用 stream 4, 9, 16, 25, 36, ...的正方形,然后合並到 stream 8, 27, 64, ...的立方體,stream 16, 81, 256, ...的四次方,等等。 我們需要做的就是跟蹤每個 stream 的下一個元素,當我們想要下一個最高的完美功率時,我們掃描這些下一個元素並拉出最低的一個,同時推進 stream。

作為一項額外的改進,如果我們將每個流的頭部保持在合適的數據結構中,我們可以高效地檢索下一個最小元素,而無需搜索整個列表。 一種合適的結構是二進制堆,Python 的標准庫提供了heapq模塊來形成和操作堆。

這是基於上述想法的完美冪序列的簡單生成器:

from heapq import heappop, heappush

def perfect_powers():
    """ Generate the sequence of perfect powers: 4, 8, 9, 16, 25, ... """
    next = [(4, 2, 2)]
    last = 1
    while True:
        power, base, exponent = heappop(next)
        if power > last:
            yield power
            last = power
        heappush(next, ((base+1)**exponent, base+1, exponent))
        if base == 2:
            heappush(next, (power*base, base, exponent+1))

在任何給定時間,堆下一個包含每個 stream 的next一個元素,元素的形式為(power, base, exponent) (例如,冪125顯示為(125, 5, 3) )。 此外,每當我們從堆中拉出 2 的冪(例如2**6 )時,我們將下一個 stream 的第一個元素添加到堆中 - 在本例中是 7 次方的 stream,從2**7開始2**7

以下是上述生成的前 15 個元素:

>>> import itertools
>>> list(itertools.islice(perfect_powers(), 15))
[4, 8, 9, 16, 25, 27, 32, 36, 49, 64, 81, 100, 121, 125, 128]

一些偶然的時間,由 IPython 提供,表明這種方法可以很好地適應術語的數量:

In [1]: import itertools                                                                                          

In [2]: %timeit list(itertools.islice(perfect_powers(), 15))                                                      
11 µs ± 20.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [3]: %timeit list(itertools.islice(perfect_powers(), 150))                                                     
112 µs ± 717 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [4]: %timeit list(itertools.islice(perfect_powers(), 1500))                                                    
1.19 ms ± 10.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [5]: %timeit list(itertools.islice(perfect_powers(), 15000))                                                   
11.9 ms ± 50.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [6]: %timeit list(itertools.islice(perfect_powers(), 150000))                                                  
130 ms ± 1.94 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [7]: %timeit list(itertools.islice(perfect_powers(), 1500000))                                                 
1.37 s ± 29 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

不到1.5秒就產生了第一個150萬完美的力量!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM