如何找到整数第n个根?

Col*_*nic 15 python algorithm math

我想找到小于或等于n的第k个根的最大整数.我试过了

int(n**(1/k))
Run Code Online (Sandbox Code Playgroud)

但是对于n = 125,k = 3,这给出了错误的答案!我碰巧知道5立方是125.

>>> int(125**(1/3))
4
Run Code Online (Sandbox Code Playgroud)

什么是更好的算法?


背景:2011年,这次失误让我击败Google Code Jam.https://code.google.com/codejam/contest/dashboard?c=1150486#s=p2

NPE*_*NPE 14

怎么样:

def nth_root(val, n):
    ret = int(val**(1./n))
    return ret + 1 if (ret + 1) ** n == val else ret

print nth_root(124, 3)
print nth_root(125, 3)
print nth_root(126, 3)
print nth_root(1, 100)
Run Code Online (Sandbox Code Playgroud)

在这里,无论是valn预期是整数和积极的.这使得return表达式完全依赖于整数运算,消除了舍入错误的任何可能性.

请注意,只有在val**(1./n)相当小的情况下才能保证准确性.一旦该表达式的结果偏离真实答案超过1,该方法将不再给出正确答案(它将给出与原始版本相同的近似答案).

不过我很奇怪,为什么int(125**(1/3))4

In [1]: '%.20f' % 125**(1./3)
Out[1]: '4.99999999999999911182'
Run Code Online (Sandbox Code Playgroud)

int()截断到4.

  • @Andrey:尝试在解释器中输入`125**(1./3)`.你应该得到像`4.999999999999999`,而不是`5`.`int`将它置于`4`. (2认同)
  • 小心大数:nth_root((10**20 + 2)**2,2)= 10**20与本答案中的方法. (2认同)

use*_*810 11

一个解决方案首先将lo和hi之间的答案括起来,重复乘以2直到n在lo和hi之间,然后使用二进制搜索来计算确切的答案:

def iroot(k, n):
    hi = 1
    while pow(hi, k) < n:
        hi *= 2
    lo = hi / 2
    while hi - lo > 1:
        mid = (lo + hi) // 2
        midToK = pow(mid, k)
        if midToK < n:
            lo = mid
        elif n < midToK:
            hi = mid
        else:
            return mid
    if pow(hi, k) == n:
        return hi
    else:
        return lo
Run Code Online (Sandbox Code Playgroud)

另一种解决方案使用牛顿方法,它在整数上运行得非常好:

def iroot(k, n):
    u, s = n, n+1
    while u < s:
        s = u
        t = (k-1) * s + n // pow(s, k-1)
        u = t // k
    return s
Run Code Online (Sandbox Code Playgroud)