繁体   English   中英

Codewars Buddy Pairs Kata 优化 Python 解决方案

[英]Codewars Buddy Pairs Kata Optimize Python Solution

这是卡塔链接: https : //www.codewars.com/kata/59ccf051dcc4050f7800008f/shell

好友对 你知道一个数的除数是什么。 当你只考虑除 n 本身以外的除数时,正整数 n 的除数被称为适当的。 在以下描述中,除数将意味着适当的除数。 例如,对于 100,它们是 1、2、4、5、10、20、25 和 50。

让 s(n) 是这些 n 的真除数的总和。 给好友打电话两个正整数,使得每个数字的真除数之和比另一个数字多一个:

(n, m) 是一对伙伴,如果 s(m) = n + 1 且 s(n) = m + 1

例如 48 & 75 就是这样一对:

48 的除数是:1, 2, 3, 4, 6, 8, 12, 16, 24 --> sum: 76 = 75 + 1 75 的除数是:1, 3, 5, 15, 25 --> sum : 49 = 48 + 1 任务 给定两个正整数 start 和 limit,函数 buddy(start, limit) 应该返回第一对 (nm) buddy 对,使得 n(正整数)介于 start(含)和 limit(包括的); m 可以大于 limit 并且必须大于 n

如果没有满足条件的伙伴对,则返回“Nothing”或(对于 Go lang)nil 或(对于 Dart)null; (对于 Lua、Pascal、Perl)[-1,-1]。

test.assert_equals(buddy(10, 50), [48, 75])

test.assert_equals(buddy(2177, 4357), "Nothing")

test.assert_equals(buddy(57345, 90061), [62744, 75495])

test.assert_equals(buddy(1071625, 1103735), [1081184, 1331967])

这是我的解决方案,但我收到Execution Timed Out错误花费了太多时间:

def sum_divisors(num):
    sum = 0
    for i in range(1, num):
        if num % i == 0:
            sum += i

    return sum


def buddy(start, limit):
    for i in range(start, limit + 1):
        sum = sum_divisors(i)
        sum_minus_one = sum_divisors(sum - 1)

        if start > sum - 1:
            continue

        if i == (sum_minus_one - 1):
            return [i, sum - 1]

    return "Nothing"

一些优化:

要找到除数的总和:

  • 1 总是一个除数,所以只需计算它并从 2 开始循环
  • 只需循环到 N 的平方根,并计算您找到的两个除数(例如,4 是 100 的除数,因此100//4 = 25 也是一个除数); 但请记住避免计算平方根两次
def divisors(n):
    divsum = 1
    for i in range(2,int(sqrt(n))+1):
        d,m = divmod(n,i)
        if m == 0:
            divsum += i
            if i != d:
                divsum += n // i
    return divsum

寻找好友:

  • 计算第二个和之前检查 N 的除数之和是否低于start (如果是,则continue
  • 还要检查 N 的除数之和是否小于 M(如果是,也continue
def buddy(start,limit):
    for i in range(start, limit+1):
        sum1 = divisors(i)
        if start > sum1-1 or i > sum1:
            continue
        sum_minus1 = divisors(sum1 - 1)
        if i == (sum_minus1 - 1):
            return [i, sum1 - 1]
    else:
        return "Nothing"

下面是一种根据一个数的质因数分解找到一个数的除数之和的快速方法:

from math import isqrt

def sum_of_divisors(n):
    result = 1
    div = 1
    while True:
        for div in range(div + 1, isqrt(n) + 1):
            if not n % div:
                mul = 1
                while not n % div:
                    n //= div
                    mul = 1 + mul * div
                result *= mul
                break
        else:
            if n > 1:
                result *= 1 + n
            return result

考虑例如 n=100。 除数是质因数的乘积,例如除数 50 是 2×5²。

最初已知的素因数:无
素因子的可能乘积:只有值为 1 的空乘积。
这些产品的总和:1

找到质因数 2(两次)后:
可能的乘积:先前乘积乘以 2 0 、2 1或 2 2
乘积之和:前面的和乘以(1+2+4),即1×7=7。

找到质因数 5(两次)后:
可能的乘积:先前乘积乘以 5 0 、 5 1或 5 2
乘积之和:前面的和乘以(1+5+25),即7×31=217。

如果你减去 n 本身,你会得到 117,这也是 1、2、4、5、10、20、25 和 50(任务描述中列出的适当除数列表)的总和。

我的buddy功能使用上述内容:

def buddy(start, limit):
    def s(n):
        return sum_of_divisors(n) - n
    for n in range(start, limit + 1):
        m = s(n) - 1
        if m > n and s(m) == n + 1:
            return [n, m]
    return 'Nothing'

在 Codewars 的最大案例中将我的与 gimix 进行比较, buddy(145_809_719, 145_812_719)

Kelly:  0.84 seconds
gimix: 10.57 seconds

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM