【问题标题】:How to make perfect power algorithm more efficient?如何让完美幂算法更高效?
【发布时间】:2016-08-28 11:32:02
【问题描述】:

我有以下代码:

def isPP(n):
  pos = [int(i) for i in range(n+1)]
  pos = pos[2:] ##to ignore the trivial n** 1 == n case
  y = []
  for i in pos:
      for it in pos:
          if i** it == n:
              y.append((i,it))
              #return list((i,it))
      #break
  if len(y) <1:
      return None
  else:
      return list(y[0])

这在 2000 年之前都可以正常工作,因为我在内存中存储了太多。我该怎么做才能使它有效地处理大量(例如,50000 或 100000)。我在找到一个案例后试图让它结束,但是如果数量很大,我的算法仍然效率太低。

有什么建议吗?

【问题讨论】:

  • 你应该意识到这不是2 的力量,早在你到达检查2 ** 99999 == 100000 的地步之前......
  • 从不考虑破坏如果我**它> n.
  • @nodel,你应该使用日志。我写了一个解释代码和逻辑的答案。看看这是否回答了问题和要求。

标签: python algorithm python-3.x


【解决方案1】:

如果存在一个 b 和 e 且 b^e = n。例如 216 = 6^3 = 2^3 * 3^3 是完美幂,但 72 = 2^3 * 3^2 不是。

判断一个数是否是完美幂的诀窍是要知道,如果该数是完美幂,那么指数 e 必须小于 log2 n,因为如果 e 大于 2^e 将大于 n。此外,只需要测试素数 es,因为如果一个数是复合指数的完美幂,那么它也将是复合分量的素因数的完美幂;例如,2^15 = 32768 = 32^3 = 8^5 是一个完美的立方根,也是一个完美的五次根。

下面显示的函数isPerfectPower 测试每个小于log2 n的素数,首先使用牛顿法计算整数根,然后对结果进行运算以检查它是否等于n。辅助函数primes 通过埃拉托色尼筛法计算素数列表,iroot 通过牛顿法计算整数 k 次根,ilog 计算以 b 通过二分查找。

def primes(n): # sieve of eratosthenes
    i, p, ps, m = 0, 3, [2], n // 2
    sieve = [True] * m
    while p <= n:
        if sieve[i]:
            ps.append(p)
            for j in range((p*p-3)/2, m, p):
                sieve[j] = False
        i, p = i+1, p+2
    return ps

def iroot(k, n): # assume n > 0
    u, s, k1 = n, n+1, k-1
    while u < s:
        s = u
        u = (k1 * u + n // u ** k1) // k
    return s

def ilog(b, n): # max e where b**e <= n
    lo, blo, hi, bhi = 0, 1, 1, b
    while bhi < n:
        lo, blo, hi, bhi = hi, bhi, hi+hi, bhi*bhi
    while 1 < (hi - lo):
        mid = (lo + hi) // 2
        bmid = blo * pow(b, (mid - lo))
        if n < bmid: hi, bhi = mid, bmid
        elif bmid < n: lo, blo = mid, bmid
        else: return mid
    if bhi == n: return hi
    return lo

def isPerfectPower(n): # x if n == x ** y, or False
    for p in primes(ilog(2,n)):
        x = iroot(p, n)
        if pow(x, p) == n: return x
    return False

在my blog 有关于完美幂谓词的进一步讨论。

【讨论】:

    【解决方案2】:

    IIRC,迭代检查“它有平方根吗?它有立方根吗?它有第四个根吗?......”你会很快到达推定根必须的地步介于1 和2 之间,此时您可以停止。

    【讨论】:

    • 我试图实现这一点,但在 python 中,1000**(1/3) =9.999999999999998。我将如何解决这个问题,同时保持解决方案的完整性(忽略错误匹配)?
    • @nodel:使用精确的方法来判断它是否有立方根。
    【解决方案3】:

    一个相关的改进是:

    import math
    
    def isPP(n):
    
            # first have a look at the length of n in binary representation
            ln = int(math.log(n)/math.log(2)) + 1
    
            y = []
            for i in range(n+1):
                    if (i <= 1):
                            continue
                    # calculate max power
    
                    li = int(math.log(i)/math.log(2))
                    mxi = ln / li + 1
                    for it in range(mxi):
                            if (it <= 1):
                                    continue
                            if i ** it == n:
                                    y.append((i,it))
                                    # break if you only need 1
    
            if len(y) <1:
                    return None
            else:
                    return list(y[0])
    

    【讨论】:

      【解决方案4】:

      我认为更好的方法是实现这个“hack”:

      import math
      
      def isPP(n):
          range = math.log(n)/math.log(2)
          range = (int)(range)
          result = []
          for i in xrange(n):
              if(i<=1):
                  continue
              exponent = (int)(math.log(n)/math.log(i))
              for j in [exponent-1, exponent, exponent+1]:
                  if i ** j == n:
                      result.append([i,j])
          return result
      
      print isPP(10000)
      

      结果:

      [[10,4],[100,2]]
      

      黑客使用以下事实:

      if log(a)/log(b) = c,
          then power(b,c) = a
      

      由于这个计算在浮点数中可能会有点偏差,给出真正近似的结果,因此检查指数的准确性为+/- 1。

      您可以进行必要的调整以处理诸如n=1, etc. 之类的极端情况

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-10
        • 2011-11-14
        • 2020-07-26
        • 2014-02-11
        相关资源
        最近更新 更多