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

Python (帮助)在给定的数字字符串中查找的代码,python,Python,拉马努扬非常喜欢玩数字游戏。一天拉马努扬和 安妮什玩了一个游戏。拉马努扬给了安妮什一个数字串,然后问道 让他找到所有大小不同的子串,最多六个 首要的安妮什擅长数学,如果他能 Ramanujan为他提供的所有输入集的解决方案,Anish赢得 游戏你的任务是帮助安妮什赢得比赛 输入格式: 第一行包含T,测试用例的数量。每个测试用例 包含大小为N的字符串,该字符串仅包含整数 约束条件: 1你没有达到时限。在我的基于Xeon的系统上,你的prime函数可以以每秒8次的速度处理10^6左右的prime。由

拉马努扬非常喜欢玩数字游戏。一天拉马努扬和 安妮什玩了一个游戏。拉马努扬给了安妮什一个数字串,然后问道 让他找到所有大小不同的子串,最多六个 首要的安妮什擅长数学,如果他能 Ramanujan为他提供的所有输入集的解决方案,Anish赢得 游戏你的任务是帮助安妮什赢得比赛

输入格式:

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

约束条件:


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

首先,有两个简单的限制将大大加快速度:

  • 只除以素数。如果一个数字可以被4整除,你已经注意到它可以被2整除。要确定289不是素数,不需要对4、6、8、9、10、12
  • 停止在数字的平方根处寻找因子。任何大于sqrt的因子的同源词必须小于sqrt
  • 您可以通过简单的浏览器搜索找到这两个测试

    除此之外,通过维护素数列表,可以大大提高速度。首先,将它们用作除数;第二,测试是否包含在列表中。对于你得到的输入,记忆新发现的素数有什么意义吗


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

    有不同的方法使代码更快。例如,
    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
    
    为了测试prim编号,您不需要将每个编号与此编号进行核对。事实上,只检查prim数就足够了,直到可能数的平方根为止。上述代码还利用了一个事实,即所有大于3的prim数字都可以用6n±1的形式写入(请参阅)

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

    # 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)
    

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

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

    首先,在
    get_all_substring()
    中,没有必要让
    alist
    真正成为一个列表,而不仅仅是一个集合,它甚至不需要在最后更改。使用
    .add()
    而不是
    .append()

    其次,您可以通过以下两种方式节省构建列表
    a
    的时间:

    • 除非我弄错了,否则不需要分类。尽管如果您使用@Prune建议存储已找到的素数,排序可能会有所帮助
    • 我们可以在计算完子字符串后立即将其转换为整数。所以我们会有类似于
      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]
    

    我希望通过根本不生成那些太长的子字符串,并避免创建重复的子字符串,您可以做得更好,因为这样可以消除对集合的需要。

    这是代码战还是其他原因造成的问题?如果你得到了正确的结果,但是超时了,那是因为你的程序是正确的,但是太慢了。你需要想出加速的方法,甚至可能是一个完全不同的算法。你的方法是什么?非常感谢你,你消除了我的很多疑问。谢谢你,这真的很有帮助,先生。@Dbug On stackoverflow“谢谢”正在接受+向上投票的答案;)不过还是欢迎你;)谢谢,这给了我一个关于代码优化的想法,我希望在将来的代码中更好地应用它们
    a = [val for val in get_all_substrings(input().strip) if val > 999999]