针对此Codejam问题,Python中更快或更高内存的解决方案

时间:2010-03-27 14:59:17

标签: python puzzle

我尝试了这个Google Codejam Africa问题(比赛已经结束,我只是为了提高我的编程技巧)。

  

问题:

     

您正在与G嘉宾举办派对   并注意到有一个奇数   客人!在策划派对时你   故意邀请只有情侣和   给每对夫妇一个独特的号码C.   他们的邀请。你想要...吗   挑出任何一个人来的人   向所有客人询问他们的   邀请号码。

     

输入:

     

第一行输入给出了案例数N.   N个测试用例如下。对于每个测试用例,将有:

     
      
  • 一行包含值G the   客人数量。
  •   
  • 一行包含   以空格分隔的G整数列表。   每个整数C表示   客人的邀请码。输出
  •   
     

对于每个测试用例,输出一行   包含“Case #x:”后面跟着   单独客人的C号。

     

限制:

     
      
  • 1≤N≤50
  •   
  • 0< C≤2147483647
  •   
     

小数据集

     

3≤G< 100

     

大型数据集

     

3≤G< 1000

示例输入:

3
3
1 2147483647 2147483647
5
3 4 7 4 3
5
2 10 2 10 5

示例输出:

Case #1: 1
Case #2: 7
Case #3: 5

这是我提出的解决方案:

with open('A-large-practice.in') as f:
    lines = f.readlines()

with open('A-large-practice.out', 'w') as output:
    N = int(lines[0])
    for testcase, i in enumerate(range(1,2*N,2)):
        G = int(lines[i])
        for guest in range(G):
            codes = map(int, lines[i+1].split(' '))
            alone = (c for c in codes if codes.count(c)==1)
        output.write("Case #%d: %d\n" % (testcase+1, alone.next()))

使用large input在我的机器上运行12秒。

现在,我的问题是,这个解决方案可以在Python中改进,以便在更短的时间内运行或使用更少的内存吗?该问题的analysis给出了一些关于如何在Java和C ++中执行此操作的指示,但我无法将这些解决方案转换回Python。

修改

结合Alex Martelli和IVlad的提示我现在有了这个解决方案,运行时间为0.079s:

with open('A-large-practice.in') as f:
    lines = f.readlines()

with open('A-large-practice.out', 'w') as output:
    N = int(lines[0])
    for testcase, i in enumerate(range(1,2*N,2)):
        codes = map(int, lines[i+1].split(' '))
        alone = 0
        for c in codes: alone ^= c
        output.write("Case #%d: %d" % (testcase+1, alone))

5 个答案:

答案 0 :(得分:5)

我不知道python,但问题本身就是经典。给定2K - 1个数字,除了一个出现偶数次的数字外,找到一个出现奇数次的数字。

需要的公式:

  1. x xor x == 0 for all x
  2. x xor y == y xor x for all x and y
  3. x xor (y xor z) == (x xor y) xor z (associativity)
  4. x xor 0 == x for all x
  5. 所以xor所有数字。 xor-ing所有数字的结果将是你的答案。我不知道你在python中是怎么做的,在C语言中xor运算符是^

    这是最有效的方法,因为您只进行简单的按位操作,甚至不必存储给定的数字。

    您可以检查: 3 ^ 4 ^ 7 ^ 4 ^ 3 == 72 ^ 10 ^ 2 ^ 10 ^ 5 == 5等。

答案 1 :(得分:4)

我的机器比你的慢 - 你的代码(放入main功能)在我的机器上耗时19秒。删除无用内部for的明显优化将此切割为0.46秒;将代码的核心改为

      alone = 0
      for c in codes: alone ^= c

将时间缩短为0.08秒。我确信可以进一步优化,但代码已经快了235倍,我认为这可能就足够了; - )。

答案 2 :(得分:2)

考虑一下:

codes = map(int, lines[i+1].split(' '))

为什么为guest的每个值重新分隔行?这条线不会改变。

另外,请考虑一下:

for guest in range(G):
    codes = map(int, lines[i+1].split(' '))
    alone = (c for c in codes if codes.count(c)==1)

此循环中的所有代码都不依赖于guest。为什么它在循环中?

答案 3 :(得分:1)

这对我来说立即结束,结果相同:

src = open('A-large-practice.in')
dst = open('A-large-practice.out', 'w')

n = int(src.readline().rstrip())
for i in xrange(n):
    src.readline() # skip g
    nums = src.readline().split()
    seen = set()
    for n in nums:
        if n in seen:
            seen.remove(n)
        else:
            seen.add(n)
    dst.write("Case #%d: %s\n" % (i+1, tuple(seen)[0]))

src.close()
dst.close()

该死的,我喜欢哈希地图!

答案 4 :(得分:1)

是的,正如分析页面所解释的那样,您可以使用常量内存,但任何方法都将在O(n)时间内运行。以下是常量内存解决方案在Python中的工作方式:

numbers = [1, 1, 2, 2, 3, 3, 4, 4, 12345]
missingOne = 0
for number in numbers:
    missingOne = missingOne ^ number
assert missingOne == 12345

关键是要了解xor运算符的作用。任何与零相关的数字本身。任何与自身相关的数字都是零。如果你查看xor的真值表,你应该能够说服自己这两个事实,然后证明从列表开始,从零开始编号将产生非重复的数字。