如何修改此Python代码(如果需要)以提高效率?

时间:2016-11-02 07:49:01

标签: python performance

因此,您将获得一个整数n,它对应于您拥有的宽松袜子的数量。然后给出一个袜子列表,其编号与其标签/颜色相对应。

例如,Sample输入:

9
10 20 20 10 10 30 50 10 20

输出:

3

在这种情况下,对是(10,10), (20,20), (10,10),因为每个袜子只能使用一次。

通过找到一对并将每个标记标记为-1以表示已经位于一对中的袜子,我能够找到问题的解决方案。我的第一个解决方案似乎效率低下,因为循环遍历了包含-1的值,所以我使用了上周我在课堂上学到的break and continue

这是我最近的解决方案:

import sys


n = int(input().strip())
c = [int(c_temp) for c_temp in input().strip().split(' ')]

matching = 0
pairFound = True 

while pairFound:
    pairFound = False
    for i in range(len(c)):
        if c[i] == -1:
            continue
        for j in range(i+1,len(c)):
            if c[j] == -1:
                continue
            if c[i] == c[j] and c[i] != -1 and c[j] != -1:
                pairFound=True
                matching = matching + 1
                c[i]=-1
                c[j]=-1
            if c[i] == -1:
                break
print(matching)

我写的代码有多高效?

我并不是在寻找替代解决方案,我更感兴趣的是调整方法以使我现有的代码更好。

谢谢你们。

3 个答案:

答案 0 :(得分:2)

您的代码效率不高,因为它的运行时间与元素数量(即socks)的平方成正比。您可以通过计算元素并获取(number_elements // 2)的总和来实现线性运行时。如果真的对运行时感兴趣,我建议使用模块集合中的Counter类。

答案 1 :(得分:2)

对于正在编程的第一步的人来说,从概念的角度来看,你的方法是完全可以的:

  • 好消息是,您只需将第一个for循环中每个项目的后续列表考虑在内,而不是遍历整个列表。

  • 糟糕的是,可能会让您认为可以改进这一点,即标记已分配一对的袜子而不是从列表中删除它们。删除它们会缩短列表,从而减少完成任务所需的计算步骤。但是,在迭代它时从列表中删除项目是一个坏主意,所以你需要一些不同的东西。

  • 此外,您可以省略封闭的while循环,因为第一个for循环无论如何都会在到达袜子序列结束时结束。当你到达结束时访问后续列表时,请注意IndexError

我怀疑你在课堂上已经涵盖了递归,但这是一种迭代更改列表并同时收集无法分配给一对的项目的有效方法(即< em>孤独的袜子)。

递归是关于从自身调用函数:

socks成为您的输入列表。您可以将其拆分为head(第一个元素)和rest(所有其他元素)。

socks = [10, 20, 10, 40]
head = socks[0] # Here, head will be 10
rest = socks[1:] # Here, rest will be [20, 10, 40]

首先,您需要在rest中搜索等于head的元素。找到后,您可以将其从rest中删除,因为它无法配对多次:

for i, s in enumerate(rest):
    if s == head:
        match = rest.pop(i)
        break

现在执行此步骤后,您知道找到了由headmatch元素组成的对。并且,您的rest列表已更改:您已删除匹配的部分:

[20, 40]

您可以重复这些步骤,直到rest列表的长度为<= 1,因此我们需要在此处再次运行,其中head20且{{1将是rest。迭代[40]不会产生一对,我们应该按原样返回。

一旦你的迭代达到了rest的长度rest,你可以退出,因为你知道你必须找到所有对。

在代码中,这可能如下所示:

<= 1

此代码的输出类似于:

import random

def seek_pair(lst):
    if len(lst) <= 1:
        # Nothing to do if we cannot split list into head and rest
        return lst

    # Split list into head and rest
    head, rest = lst[0], lst[1:]

    # Iterate over rest and try to find a match
    match = None
    for i, s in enumerate(rest):
        if s == head:
            # We have found an element that equals our head
            # Remove it from the list and store it in variable 'match'
            match = rest.pop(i)
            # Break the loop as we have found a match
            break

    if match:
        # If there was a match in the 'rest' list, we can print it
        print('Pair: ({:d}, {:d})'.format(head, match))
        # And call the method 'seek_pair()' on the resulting 'rest'
        # Note that here, the matching element has already been
        # removed from the list 'rest'.
        return seek_pair(rest) # RECURSION
    else:
        # If no match was found, we still need to search the 'rest'
        # list for other matches.
        # And, since 'head' did not match any other element, we append
        # it to the beginning of our result list, which will hold all
        # elements without matches (i.e. lonely socks).
        return [head] + seek_pair(rest) # RECURSION

if __name__ == '__main__':
    # Randomly generate an input list of desired length
    n = 9
    socks = [random.randint(1, 9) * 10 for _ in range(n)]

    # Print the list
    print('Socks: {:s}'.format(', '.join([str(s) for s in socks])))
    # Call the function on the entire list and obtain its result,
    # that should contain all lonely socks.
    rest = seek_pair(socks)
    # Print lonely socks
    print('Rest: {:s}'.format(', '.join([str(s) for s in rest])))

答案 2 :(得分:0)

我的解决方案使用collections.Counter

>>> import collections
>>> c = [10, 20, 20, 10, 10, 30, 50, 10, 20]
>>> sum([int(i/2) for i in collections.Counter(c).values()])
>>> 3

如果想获得重复对的详细信息,请使用下面的代码。显示我们有4次出现10次,3次出现20次等等最多发生命令

>>> import collections
>>> c = [10, 20, 20, 10, 10, 30, 50, 10, 20]
>>> collections.Counter(c).most_common ()
>>> [(10, 4), (20, 3), (50, 1), (30, 1)]