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)
这将根据我的自定义测试输出正确的值。您还可以打印相应的列表及其等效的布尔布尔值。
问题:我的所有结果都超时了。
问题出在什么地方和什么地方?
答案 0 :(得分:2)
除了@Prune的数学改进之外,还有一些其他的编程改进。
首先,get_all_substrings()
中不需要alist
成为列表,而不仅仅是集合。甚至不需要在末尾进行更改。使用.add()
代替.append()
。
第二,您可以通过以下几种方式来节省构建列表a
的时间:
alist.add(int(string[i:j + 1]))
的东西。这样可以节省内存,并且还可以轻松比较它们是否过长。由于我们知道9位数字的最大值(以10为基数),因此我们可以简单地检查它是否较大,这是非常快的。 i > 999999
列表理解如下:
>>> 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周的时间。简而言之,您需要研究确定数字是否为质数的更快方法。
首先,有两个简单的限制可以加快很多的速度:
您可以通过简单的浏览器搜索找到这两个测试。
除此之外,您可以通过维护素数列表来加快速度。首先,将它们用作除数;第二,测试是否包含在列表中。对于您得到的输入,是否有任何记忆力可以记住新发现的素数?
如果您想提高速度和复杂度,请查看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)
您的其余代码也可以进一步优化!