(帮助)在给定的数字字符串中查找的代码

时间:2018-11-16 16:50:20

标签: python

  

Ramanujan非常喜欢玩数字游戏。一天拉玛努詹和   阿尼什玩了一场比赛。拉曼努让(Ramanujan)给艾尼什(Anish)一个数字字符串,并询问   他最多找到六个大小不同的所有子字符串   主要。擅长数学的Anish会参加比赛,如果他愿意的话   Ramanujan为他提供的所有输入集的解决方案,Anish赢得了   游戏。您的任务是帮助Anish赢得比赛。

     

输入格式:

     

第一行包含T,测试用例的数量。每个测试用例   包含大小为N的字符串,仅包含整数。

     

约束:

     

1 <=测试用例数<= 10

     

1 <= N <= 10 ^ 7

代码:

def prime(num):
    if num > 1:
        for i in range(2, num):
            if num%i==0:
                return False
        else :
            return True
    else:
        return False

def get_all_substrings(string):
    length = len(string)
    alist = []
    for i in range(length):
        for j in range(i,length):
            alist.append(string[i:j + 1])
    for i in range(length, -1, -1):
        for j in range(length, i, -1):
            alist.append(string[i:j + 1])
    return list(set(alist))


t = int(input())
for i in range(1, t+1):
    a = list(map(int, get_all_substrings(input().strip())))
    prime_count = 0
    for i in a:
        if len(str(i))>6:
            a.remove(i)
    a.sort()
##    print(a)
##    for i in a:
##        print(i, " : " , prime(i))
    for i in a:
        if prime(i):
            prime_count +=1
    print(prime_count)

这将根据我的自定义测试输出正确的值。您还可以打印相应的列表及其等效的布尔布尔值。

问题:我的所有结果都超时了。

问题出在什么地方和什么地方?

3 个答案:

答案 0 :(得分:2)

除了@Prune的数学改进之外,还有一些其他的编程改进。

首先,get_all_substrings()中不需要alist成为列表,而不仅仅是集合。甚至不需要在末尾进行更改。使用.add()代替.append()

第二,您可以通过以下几种方式来节省构建列表a的时间:

  • 除非我弄错了,否则不需要对其进行排序。尽管排序可能会有所帮助,如果您使用@Prune的建议来存储已经找到的素数。
  • 我们可以在计算子字符串后立即将它们转换为整数。所以我们会有类似alist.add(int(string[i:j + 1]))的东西。这样可以节省内存,并且还可以轻松比较它们是否过长。由于我们知道9位数字的最大值(以10为基数),因此我们可以简单地检查它是否较大,这是非常快的。 i > 999999
  • 首先不要添加太长的条目。有一种很棒的Pythonic方式可以做到这一点。我们可以使用条件列表理解

列表理解如下:

>>> my_list = [i for i in range(10)]
>>> print(my_list)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

可以添加条件,以便仅添加所需的元素:

>>> my_list = [i for i in range(10) if i%2 == 0]
>>> print(my_list)
[0, 2, 4, 6, 8]

这等效于以下内容:

my_list = []
for i in range(10):
    if i%2 == 0:
        my_list.append(i)

因此,将它们放在一起,我们只用一行即可生成一个:

a = [val for val in get_all_substrings(input().strip) if val > 999999]

我希望您甚至可以完全不生成那些太长的子字符串,并且避免创建重复项,从而消除对集合的需求,从而做得更好。

答案 1 :(得分:1)

您没有达到时间限制。在基于Xeon的系统上,您的prime函数只能以每秒8个的速度处理大约10 ^ 6的质数。由于您必须处理最多10 ^ 7个整数的列表,因此使用此类素数大约需要2周的时间。简而言之,您需要研究确定数字是否为质数的更快方法。

首先,有两个简单的限制可以加快很多的速度:

  1. 除以素数。如果一个数字可以被4整除,您已经注意到它可以被2整除。要确定289不是质数,则无需针对4,6,8,8,9,10,12,...
  2. 停止在数字的平方根处查找因子。任何大于sqrt 的因子的同源度均小于sqrt。

您可以通过简单的浏览器搜索找到这两个测试。

除此之外,您可以通过维护素数列表来加快速度。首先,将它们用作除数;第二,测试是否包含在列表中。对于您得到的输入,是否有任何记忆力可以记住新发现的素数?

如果您想提高速度和复杂度,请查看Rabin-Miller算法的实现以进行快速素数检测。它是“唯一的”概率,但已证明对128位整数具有100%的精度,k = 7(检查的数量)。

答案 2 :(得分:1)

有多种方法可以使您的代码更快。例如,prime函数的加速将是:

def isPrimeX(n):
    if n in [2,3]: return True
    if n % 2 == 0 or n % 3 == 0: return False
    needCheckTill = int(math.sqrt(n))
    for i in range(6, needCheckTill+2, 6):
        if n % (i-1) == 0 or n % (i+1) == 0:
            return False
    return True

为了测试素数,您不需要对照该数字检查每个数字。实际上,仅检查素数到可能数的平方根就足够了。上面的代码还利用了一个事实,即所有大于3的素数都可以6n±1的形式编写(请参见https://primes.utm.edu/notes/faq/six.html)。

考虑到这一点,您可能会看到另一个加速。我们可以缓存从1到sqrt(10E7)的素数,并使用Eratosthenes的Sieve算法来计算它们:

# get a list of all prim numbers between 1 and 10E7
import math

def isPrim(n, belowPrims):
    limit = int(math.sqrt(n))
    for prim in belowPrims:
        if prim > limit: break
        if n % prim == 0: return False 
    return True

def calcPrims():
    yield 2
    yield 3
    toTest, nextN = [], 6
    while True:
        p1 = nextN - 1
        if isPrim(p1, toTest):
            yield p1
            toTest.append(p1)
        p2 = nextN + 1
        if isPrim(p2, toTest):
            yield p2
            toTest.append(p2)
        nextN += 6

limit = int(math.sqrt(10 ** 7)) + 1 
listOfPrims = []
for prim in calcPrims():
    if prim > limit:
        break
    listOfPrims.append(prim)

您的其余代码也可以进一步优化!