低至零hackerrank超过时间

时间:2016-05-09 10:51:28

标签: python algorithm factors breadth-first-search

尝试解决hackerrank problem

您将获得Q查询。每个查询由一个数字N组成。您可以在每次移动中对N执行2次操作。如果N = a×b(a≠1,b≠1),我们可以改变N = max(a,b)或将N的值减1。 确定将N值减小为0所需的最小移动次数。

我用BFS方法来解决这个问题。

一个。使用seive生成所有素数

湾使用素数我可以简单地避免计算因子

℃。我将-1和所有因素排在一起,以达到零。

d。我还使用以前的结果来排队遇到的数据。

这仍然让我超时。任何的想法?在代码中也添加了注释。

import math
#find out all the prime numbers
primes = [1]*(1000000+1)
primes[0] = 0
primes[1] = 0
for i in range(2, 1000000+1):
  if primes[i] == 1:
    j = 2
    while i*j < 1000000:
      primes[i*j] = 0
      j += 1

n = int(input())
for i in range(n):
  memoize= [-1 for i in range(1000000)]
  count = 0
  n = int(input())
  queue = []
  queue.append((n, count))
  while len(queue):
    data, count = queue.pop(0)
    if data <= 1:
      count += 1
      break   
    #if it is a prime number then just enqueue -1
    if primes[data] == 1 and memoize[data-1] == -1:
      queue.append((data-1, count+1))
      memoize[data-1] = 1
      continue
    #enqueue -1 along with all the factors
    queue.append((data-1, count+1))
    sqr = int(math.sqrt(data))
    for i in range(sqr, 1, -1):
      if data%i == 0:
        div = max(int(data/i), i)
        if memoize[div] == -1:
          memoize[div] = 1
          queue.append((div, count+1))
  print(count)

2 个答案:

答案 0 :(得分:1)

或者,有一种O(n*sqrt(n))时间和O(n)空间复杂度解决方案可以很好地通过所有测试用例。

这个想法是为每个非负整数缓存最小计数,最多1,000,000(问题中的最大可能输入数字)!!! 在运行之前!查询。这样做之后,对于每个查询,只需为存储在缓存中的给定数字返回一个最小计数。因此,每次查询检索结果的时间复杂度为O(1)

要查找每个数字的最小计数(我们将其称为down2ZeroCounts),我们应考虑几种情况:

  1. 01分别具有01的最小计数。
  2. 素数p1及其本身以外没有其他因素。因此,其最小数量为1加上最小数量为p - 1或更正式地为down2ZeroCounts[p] = down2ZeroCounts[p - 1] + 1
  3. 对于复合数字num,它要复杂一些。对于a > 1,b > 1这样的num = a*b的任意一对因素,num的最小数量是down2ZeroCounts[a] + 1down2ZeroCounts[b] + 1down2ZeroCounts[num - 1] + 1

因此,我们可以按升序逐渐为每个数字建立最小计数。计算每个后续数字的最小计数将基于较小数字的最佳计数,因此最终将建立一个最佳计数列表。

要更好地理解该方法,请检查代码:

from __future__ import print_function

import os
import sys

maxNumber = 1000000
down2ZeroCounts = [None] * 1000001

def cacheDown2ZeroCounts():
    down2ZeroCounts[0] = 0
    down2ZeroCounts[1] = 1

    currentNum = 2
    while currentNum <= maxNumber:
        if down2ZeroCounts[currentNum] is None:
            down2ZeroCounts[currentNum] = down2ZeroCounts[currentNum - 1] + 1
        else:
            down2ZeroCounts[currentNum] = min(down2ZeroCounts[currentNum - 1] + 1, down2ZeroCounts[currentNum])

        for i in xrange(2, currentNum + 1):
            product = i * currentNum
            if product > maxNumber:
                break
            elif down2ZeroCounts[product] is not None:
                down2ZeroCounts[product] = min(down2ZeroCounts[product], down2ZeroCounts[currentNum] + 1)
            else:
                down2ZeroCounts[product] = down2ZeroCounts[currentNum] + 1    

        currentNum += 1

def downToZero(n):
    return down2ZeroCounts[n]

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    q = int(raw_input())

    cacheDown2ZeroCounts()
    for q_itr in xrange(q):
        n = int(raw_input())

        result = downToZero(n)

        fptr.write(str(result) + '\n')

    fptr.close()

答案 1 :(得分:0)

此代码有两个原因导致缓慢。

清除数组比清除数组

要慢

第一个问题是这一行:

memoize= [-1 for i in range(1000000)]

这将准备100万个整数,并为1000个测试用例中的每一个执行。更快的方法是简单地使用Python集来指示哪些值已经被访问过。

正在执行不必要的循环

第二个问题是这一行:

if primes[data] == 1 and memoize[data-1] == -1:

如果你有一个素数,并且你已经访问过这个数字,那么你实际上是在慢循环中搜索那些永远找不到任何解决方案的素因子(因为它是一个素数)。

更快的代码

事实上,由于使用套装而导致的改进太多,以至于您甚至不需要您的主要测试代码,以下代码会在限定时间内通过所有测试:

import math
n = int(input())
for i in range(n):
  memoize = set()
  count = 0
  n = int(input())
  queue = []
  queue.append((n, count))
  while len(queue):
    data, count = queue.pop(0)
    if data <= 1:
      if data==1:
        count += 1
      break   
    if data-1 not in memoize:
        memoize.add(data-1)
        queue.append((data-1, count+1))
    sqr = int(math.sqrt(data))
    for i in range(sqr, 1, -1):
      if data%i == 0:
        div = max(int(data/i), i)
        if div not in memoize:
          memoize.add(div)
          queue.append((div, count+1))
  print(count)