在python中优化子阵列最大/最小分析

时间:2015-03-17 03:56:25

标签: python optimization arrays

我目前正在处理一个黑客问题(找到here)。在这个问题中,您必须获取给定的数组并找到长度为N且具有最小max-min值的子数组。该页面解释它比我做得好一点。

话虽如此,我已经完成了问题并找到了我认为适用于所有情况的解决方案......但我会继续对他们提供的少数几个测试用例进行“超时”。我在下面提供了我的代码:

def maxmin(array, original, new): 
    minimum = -1
    for i in range(0, original-new-1): 
        subarray = array[i:i+(new)]
        if minimum == -1: 
            minimum = max(subarray)-min(subarray)
        else: 
            if (max(subarray)-min(subarray)) < minimum: 
                minimum = max(subarray)-min(subarray)
    return minimum 


n = input()
k = input()
candies = [input() for _ in range(0,n)]
candies.sort()
print maxmin(candies, n, k)

正如我上面所说,代码工作正常 - 但显然它不够“快”。我仍然是非常对Python的新手(作为我以前的问题的快速回顾会提示),所以我不确定如何使这个代码更加“pythonic”或者更快,一般来说。在这方面的任何帮助将非常感激。

谢谢!

2 个答案:

答案 0 :(得分:1)

你为什么要做这么多工作?

您的代码执行的操作很多,不需要这样做:

  • 我最糟糕的猜测是它制作了一堆列表副本。每个subarray = array[i:i+new]都会创建一个新列表,这很糟糕。请注意,如果您使用numpy,这不会发生,但您还有其他问题。使用同一列表中的元素会更容易,例如array[i]array[i+new-1]
  • 您无需计算最大值和最小值。列表已经排序,因此对于任何子数组,您的[0]值将是最小值,而您的[-1]值将是最大值。仅仅是数组,这意味着对于K值的子列表,从位置i开始,array[i]是最小值,array[i+K-1]是最大值。这使事情变得更加容易。
  • 这是一个极小的东西,但是您可以删除条件,而不是将最小值设置为-1以启动,将其设置为非常非常大的值。 sys.maxint当然是最安全的,但是如果你想避免导入sys,那么任何大于你预期的数字都会被视为差异。如果这样做,则第一次运行时不需要特殊情况。

或者,您可以计算迭代器中的所有值,然后将它们分开。这允许非常紧凑的代码;例如,以下工作:

N,K = (input(),input())
l=[input() for _ in range(0,N)]; l.sort()
print min(l[i+K-1]-l[i] for i in xrange(0,N-K+1)) 

答案 1 :(得分:0)

首先要注意的是,您的程序不适用于样本输入2(第三个样本)。这是一个有效的功能:

def maxmin2(array, n, k):
    def unfairness(sub): return max(sub) - min(sub)

    _min = 1e19                 # Sufficiently large to never happen, given the constraints
    for i in range(n-k+1):
        sub = array[i:i+k]      # Extract a k length sublist, starting at index i
        u = unfairness(sub)
        if u < _min: _min = u
    return _min

由于这是一个挑战,我会留下两个函数之间的差异。

使用它们,添加调试打印语句等。如果你无法搞清楚,我会在几分钟内编辑一个可以作为伪扰码标记的差异的链接。< /秒>

<强>差分

它太小我决定不再经历所有的麻烦。问题在于您的范围函数的上限:

range(0, original-new-1)

上限original-new-1接近但稍微偏离。

考虑n=5k=2 - 您的上限为5-2-1 = 2.

因此,由于范围排除了上限,我将是0,1

所以我们要生成子列表:

  • i=0,sublist = 0,1,2
  • 中的元素
  • i=1,sublist = 1,2,3
  • 中的元素

但我们永远不会触及第4和第5元素。相反,我们需要设置上限:

    range(0, original-new+1)
                         ^ Sign changed

现在我们的上限是5-2 + 1 = 4,我将是0,1,2,3。现在,我们的子列表是:

  • i=0,sublist = 0,1,2
  • 中的元素
  • i=1,sublist = 1,2,3
  • 中的元素
  • i=2,sublist = 2,3,4
  • 中的元素
  • i=3,sublist = 3,4,5
  • 中的元素

我们扫描整个清单。前两个例子给出了正确答案,因为找到了正确的答案(巧合),而不需要考虑最后2个子列表的不公平性。

注意:因为我们将数组排在第一位maxmin不是必需的 - 我们可以将不公平函数重新定义为:

def unfairness(sub): return sub[-1] - sub[0]

sub[-1]是子列表的最后一个元素,sub[0]是第一个元素。由于它已经排序,我们知道它们分别是子列表的最大值和最小值。此外,我们可以通过以下方式完全消除切片:

def maxmin2(array, n, k):
    _min = 1e19                 # Sufficiently large to never happen, given the constraints
    for i in xrange(n-k+1):
        u = array[i+k-1] - array[i]
        if u < _min: _min = u
    return _min