数字列表比较的Python效率> = 10,000

时间:2014-11-29 21:03:15

标签: python

我一直试图通过竞争后的最新ACM编程挑战之一来解决问题,并且一直陷入困境。问题陈述

  

您的团队由一名监督评审小组的竞赛主管保留。比赛要求评委将整数分数分配给竞争对手 - 分数越高越好。尽管该事件具有分数值的标准,但每位法官都可能以不同的方式解释这些标准。比方说,100分可能对不同的评委意味着不同的事情。

     

导演的主要目标是确定哪些参赛者应该获得顶级位置的奖品。虽然绝对分数可能因法官而不同,但导演意识到相对排名提供了所需的信息 - 如果两名法官对同一竞争者排名第一,第二,第三,......那么他们就谁应该获得奖品达成一致。

     

您的团队将编写一个程序,通过比较评委对的分数来协助导演。该计划是按竞争对手的顺序阅读两个整数分数列表,并确定评委不同意的最高排名(第一名最高)。

     

您的计划输入将是一系列得分列表对。每对以单个整数开始,给出竞争者的数量N,1< N< 1,000,000。接下来的N个整数是来自竞争对手排名的第一位裁判的得分。其次是第二位法官的分数 - N个整数,也是竞争者的顺序。分数在0到100,000,000之间(包括0和100,000)。法官不允许发表关系,因此每位法官的得分都是独一无二的。值通过一个或多个空格和/或换行符彼此分开。最后一个得分列表对后面是文件结束指示符。

存在覆盖N = 4且N = 8

的示例测试用例
  

4

     

3 8 6 2

     

15 37 17 3

     

8

     

80 60 40 20 10 30 50 70

     

160 100 120 80 20 60 90 135

预期输出: 对于每个分数对,打印一行,其中整数代表评委不同意的最高排名位置。如果评委同意每个地方,请打印一行只包含“同意”字样的行。使用下面的格式:“案例”,一个空格,案例编号,冒号和一个空格,以及没有尾随空格的案例的答案。

  

案例1:同意

     

案例2:3

我的代码如下:

import sys

def calculate(competitors, scores1, scores2):
    scores1sort = sorted(scores1, reverse = True)
    scores2sort = sorted(scores2, reverse = True)

    for x in range(len(scores1)) :
        indexed1 = scores1.index(scores1sort[x])
        #print ('place: ', x+1, 'Position: ',indexed1+1)
    #iterating over the entire length  of the sorted lists multiple times takes too long
        indexed2 = scores2.index(scores2sort[x])
        #print ('place: ', x+1, 'Position: ',indexed2+1)
        if indexed2 != indexed1 :
            print ( "Case",  str(case) + ":", x+1)
            return

    #run both fors at the same time, compare indexed of scores1 to index of scores2
    #if the position(indexed + 1) doesnt match between the two, print the place(x+1) of the disparity


    #if match:
        #print ("Case " + case +": " + "agree"
    #else: print (Case " + case + ": " + index of disagreement

    print ("Case", str(case) + ":" , "agree")



    scores1 = [];
    scores2 = [];
    case = 1;
    state = 0;
    # 0 indicates number of competitors
    # 1 indicates judge 1
    # 2 indicates judge 2
    #for line in sys.stdin:
    for line in test.split("\n"):
        line = line.strip().split()
        if not line:
            continue

    if state == 0:
        #if empty line, error
        competitors = int(line[0])
        state = 1;

    else:
        for y in line:
            if state == 1:
                scores1.append(int(y))
                if len(scores1) >= competitors:
                    state = 2;
            elif state == 2:
                scores2.append(int(y))
                if len(scores2) >= competitors:
                    state = 0;
                    #print (competitors, score1, scores2)
                    calculate(competitors, scores1, scores2);
                    case += 1;

我的代码目前使用的文本文件运行,其中包含来自编程竞赛的测试输入,其中包括小测试值,但还包括一组具有10,000个竞争对手的值。

我毫不怀疑,如果有足够的时间,代码可以完成,但编程挑战指南规定代码必须在比当前运行时短的时间窗口中运行。

因此,我想询问任何人如何优化我的代码以加快执行速度的任何提示。

4 个答案:

答案 0 :(得分:1)

提供样本输入会有所帮助。 此时,似乎您在索引方法调用和内存分配范围内(如果在py2上运行)丢失时间。 尝试使用枚举以避免编制索引。

答案 1 :(得分:1)

现在你的程序正在以二次方运行,因此当N变大时,运行时间会急剧增加。您必须在内部循环中完成工作,远低于O(n)以处理更大的数据集。

此外,简单地在开始时对输入进行排序对您没有帮助,因为您丢失了两个数组中相关条目之间的映射。

这样的事情怎么样:

def calculate(N, scores1, scores2):
    ranked1 = sorted(enumerate(scores1),key=lambda x: x[1], reverse=True)
    ranked2 = sorted(enumerate(scores2),key=lambda x: x[1], reverse=True)
    ...

现在你有两个数组,从最高排名到最低排序,成本为O(n log n),你可以只搜索排名1 [i] [0]!= ranking2 [i] [0]的情况最糟糕的是O(n)。

因此,整体运行时间为O(n + n log n)最差情况

答案 2 :(得分:0)

而不是使用list.index()函数使用二进制搜索,因为列表将被排序。 list.index内部执行线性搜索,至少在CPython中,源代码here

O(n)搜索转换为O(log n)应该会留出足够的时间让它通过。

答案 3 :(得分:0)

如上所述,使用enumerate帮助,注释内联:

import operator
def foo(one, two):
    index = operator.itemgetter(0)
    score = operator.itemgetter(1)
    # Use enumerate to create a list of (index, score) tuples
    one = list(enumerate(one))
    two = list(enumerate(two))

    # sort the tuple lists on item one using operator.itemgetter
    one.sort(key = score, reverse = True)
    two.sort(key = score, reverse = True)

    # are the indices in the same order?
    for n, (a, b) in enumerate(zip(one, two)):
        # if not find return the rank
        if index(a) != index(b):
            return n + 1
    # yes!
    return 'agree'



one = [3, 8, 6, 2]
two = [15, 37, 17, 3]
print foo(one, two)    # agree
one = [80, 60, 40, 20, 10, 30, 50, 70]
two = [160, 100, 120, 80, 20, 60, 90, 135]
print foo(one, two)    # 3