找到减少的分数

时间:2017-08-26 01:32:09

标签: python

过去两天我一直在研究这个问题。我觉得我很危险;但事情并没有完全点击。希望能有一双新鲜的眼睛来完成任何建议。

任务是找出任何分母的完全减少的分数。 蛮力在一定程度上起作用,但我需要能够找到超过10 ^ 10的结果。完整的挑战在这里:

https://www.codewars.com/kata/number-of-proper-fractions-with-denominator-d/train/python

我的代码目前在哪里:

def proper_fractions(n):
    if n < 1:
        return 0

    numbers = set(range(int(n * 0.5), 1, -1))
    primes = []
    while numbers:
        p = numbers.pop()
        primes.append(p)
        numbers.difference_update(set(range(p * 2, n + 1, p)))

    counter = n

    for num in primes:
        if n % num == 0:
            counter = counter - (n//num)
            n = n//num
            if num >= (n ** 0.5):
                break

    if n == 1:
        return counter
    elif n > 1:
        return counter - (counter // n)

3 个答案:

答案 0 :(得分:4)

您需要计算的数字称为Euler's Totient Functionn1之间n个互译的数量。

如果n的主要分解是:

prime decomposotion of n

它的欧拉函数是:

Euler's totient function formula

以伪代码计算它的算法:

  
      
  • φ = 1
  •   
  • m = n
  •   
  • 对于小于或等于p的每个素数sqrt(n):      
        
    • 如果m除以p:      
          
      • φ
      • 乘以p-1   
      • m除以p-1
      •   
    •   
    • 虽然m除以p:      
          
      • φ
      • 乘以p   
      • m除以p
      •   
    •   
  •   
  • 如果m > 1:      
        
    • //请注意,此时m必须是n大于sqrt(n)的主要因素
    •   
    • φ
    • 乘以m-1   
  •   

答案 1 :(得分:1)

您需要的是分母提供的检查以查看gcd是否为1以及是否输出到列表然后返回该列表的长度。

def proper_fractions(n):
    def gcd(x,y):
        while y:
            (x, y) = (y, x % y)
        return x
    if n <= 1:
        return 0
    else:
        count = 0
        for num in range(1,n):
            denom = gcd(n,num)
            if denom == 1:
                count += 1
        return count

答案 2 :(得分:1)

你应该使用Euler的totient函数,正如Anton用户已经说过的那样。这是解决问题的一种方法。我在代码中添加了一些注释。

def proper_fractions(n):
  distinct_prime_factors = set()   # use set to avoid duplicates
  totient_function = n
  if n == 1:
    totient_function = 0
  else:
    i = 2
    while i*i <= n:
      if n % i == 0:
        distinct_prime_factors.add(i)
        n = n/i
      else:
        i += 1
    if n > 1:
      distinct_prime_factors.add(n)   # picks up prime factors > sqrt(n)
    if len(distinct_prime_factors) == 0:   # empty set means denominator is prime
      totient_function = n - 1
    else:
      for p in distinct_prime_factors:
        totient_function = (totient_function*(p - 1))/p
  return totient_function

Euler的totient函数使用不同的素因子。这就是为什么最好使用集合而不是列表,因为集合不允许重复元素。

此外,在while循环之后,如果n大于1,则必须在素数因子集中添加n。这是因为一旦素数因子大于n的平方根,while循环就会终止。例如,考虑数字77. while循环将拾取7,因为7 * 7 = 49,小于77.但是,它不会拾取11,因为11 * 11 = 121,大于77