【问题标题】:Prime factor visitation. Flipping states based on prime factors主要因素访问。基于主要因素的翻转状态
【发布时间】:2022-02-01 04:22:28
【问题描述】:

所以我有一个 1 和 0 的列表:

[1, 1, 0, 0, 1, 1, 0, 1, 1, 1]

还有一个数字列表:[3, 4, 15]

我必须找到这些数字的所有质因数,并翻转第一个列表中与这些数字的质因数相对应的状态。

所以对于上面的例子:

数字[0] = 3,质因数只有 3

所以在状态改变后,数组看起来像:

[1, 1, 1, 0, 1, 0, 0, 1, 0, 1],所以每个 (i + 1) % 3 == 0 个位置都被翻转了

数字[1] = 4,质因数只有 2

所以在状态改变后,数组看起来像:

[1, 0, 1, 1, 1, 1, 0, 0, 0, 0]

数字[3] = 15,质因数只有 3、5

所以在状态改变后,数组看起来像:

[1, 0, 0, 1, 1, 0, 0, 0, 1, 0]

[1, 0, 0, 1, 0, 0, 0, 0, 1, 1]

这是我目前所拥有的:

from collections import Counter

def prime_factors(num):
  i = 2
  factors = []
  while i * i < = num:
    if (num % i):
      i += 1
    else:
      num //= i
      factors.append(i)
  if (num > 1):
    factors.append(num)
  return list(set(factors))

def flip(states, numbers):
  factors = []

  for num in numbers:
    factors.extend(prime_factors(num))

  facotrs = Counter(factors)

  for key, val in factors.items():
    if val % 2:
      for i in range(len(states)):
        if ((i + 1) % factor == 0):
          states[i] = 1 if states[i] == 0 else 0
    
  return states

这很好用,但对于大型列表,它是 TLE。

如何解决这个问题以使其更快?

【问题讨论】:

  • 原始问题的链接是什么?
  • 没有。这是针对一家公司的hackerrank编码挑战。我有 13/15 个测试用例通过,最后 2 个超过时间限制
  • 另外,如果这是一个OA,你应该知道问题的约束。这些限制是什么?

标签: python arrays binary primes flip


【解决方案1】:
for key, val in factors.items():
    if val % 2:
      for i in range(len(states)):
        if ((i + 1) % factor == 0):
          states[i] = 1 if states[i] == 0 else 0

在第二个 for 循环中,您不需要在 range(len(states)) 中从 0 开始。你可以从factor-1开始。

states[i] = 1 if states[i] == 0 else 0

你可以用XOR操作符替换这一行:

states[i] = states[i]^1.

【讨论】:

    【解决方案2】:

    尝试使用 Eratosthenes 筛优化素数生成器。对于小于 107

    的数字,应该在几秒钟内工作
    import math;
    
    def sieve_primes(number):
        a = [True if n>=2 and n%2==1 or n==2 else False for n in range(number+1)];
        for x in range(3, (int)(math.sqrt(number))):
            if a[x]:
                for xx in range(x*x, number, x):
                    a[xx] = False;
        primes = []
        for i in range(len(a)):
            if a[i]:
                primes.append(i);
        return primes;
    
    

    此外,您可以通过找到需要分解的最大数、为其生成素数并将其存储以供以后查找来避免多次调用素数生成器。

    【讨论】:

      【解决方案3】:

      这部分:

         for i in range(len(states)):
            if ((i + 1) % factor == 0):
              states[i] = 1 if states[i] == 0 else 0
      

      似乎太复杂了。怎么样(未经测试!):

          for i in range(factor - 1, len(states), factor):
              states[i] = 1 - states[i]
      

      ?也就是说,只直接跳转到所有索引i,这样i+1 可以被factor 整除。

      让因式分解变得非常快

      这是评论中提到的合适的筛选代码。如果最大可能数字“很大”,这当然是一种荒谬的做法。但是你没有告诉我们。如果达到几百万,这会很快。

      
      # Return list `sf` such that sf[i] is the smallest prime
      # factor of `i`, for 2 <= i <= maxn.
      def sieve(maxn):
          from math import isqrt
          sf = list(range(maxn + 1))
          for i in range(4, len(sf), 2):
              sf[i] = 2
          for p in range(3, isqrt(maxn) + 1, 2):
              if sf[p] == p:
                  for i in range(p * p, len(sf), p + p):
                      if sf[i] == i:
                          sf[i] = p
          return sf
      
      

      整件事

      这是一个完整的程序。 sieve() 的代码已经给出。一旦被调用,就再也不需要调用它了。

      通常情况下,成功完成定时“编程挑战”至关重要依赖于规定的输入约束。您多次被要求告诉我们它们是什么,但无济于事。我有根据的猜测是,他们对需要考虑的最大数量设置了相对较低的限制。这里的程序利用了这一点。但如果他们不对其进行限制,那么“快速”解决方案的希望就渺茫了,因为真正大整数的有效分解仍然是一个困难的、开放的研究问题。

      这里的方法试图平衡预处理所需的时间和空间与分解所需的时间。它可能是也可能不是“最好的”权衡,这取决于我们仍然未知的输入约束。例如,如果最大数字“非常”小,您可以预先完全计算并存储每个可能数字的唯一素因子(尽管筛法仍然是最快的简单方法)。

      # Return list of unique prime factors of n.
      def upf(n, sf):
          result = []
          while n > 1:
              p = sf[n]
              result.append(p)
              n //= p
              while n % p == 0:
                  n //= p
          return result
      
      MAXN = 1_000_000
      sf = sieve(MAXN)
      
      def crunch(nums, bits, sf):
          from collections import defaultdict
          pcount = defaultdict(int)
      
          for num in nums:
              for p in upf(num, sf):
                  pcount[p] += 1
      
          for p, count in pcount.items():
              if count & 1:
                  for i in range(p - 1, len(bits), p):
                      bits[i] = 1 - bits[i]
      
      nums = [3, 4, 15]
      bits =     [1, 1, 0, 0, 1, 1, 0, 1, 1, 1]
      expected = [1, 0, 0, 1, 0, 0, 0, 0, 1, 1]
      crunch(nums, bits, sf)
      assert bits == expected
      

      【讨论】:

      • 这个可行,但仍然有时间限制超出问题
      • 好吧,盲目地随意抽打对我们来说并不是那么有趣;-) 需要更多信息。例如,可能其中一个输入数字是一个大素数,它是分解算法一直在通过无用地除以通过其平方根的底的每个整数来咀嚼。开&开。有许多可能性 - 以及许多尝试解决它们的方法。
      • 等一下。你怎么知道@TimPeters 写的优化仍然会导致 TLE?在要求我们优化您的代码时,您没有打开 OA,对吧?
      • 不,我今天早些时候这样做了。我相信问题出在循环的某个地方。可能用于非常大的数字输入
      • 既然你不回答问题,我就放弃了。我要留给你一件事:使用类似于埃拉托色尼筛法的过程来创建一个列表sf,使得sf[i]i 的最小素因子。这是一次性成本,将使保理非常有效。但您需要提前知道可能的最大数量。
      猜你喜欢
      • 2012-08-09
      • 1970-01-01
      • 2014-02-12
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多