Python:编写一个程序来查找最大价格下降的时间段

时间:2010-11-17 13:27:30

标签: python

我想解决这个问题,但我被困住了。

编写程序,以便在给出价格清单时查找最大价格下降的时间段。例如,如果列表是[300,301,303,299,300,298,301,305],则有一个最大价格下降期间:从时间2到价格303到时间5,价格298。

以下是我的解决方案,但存在缺陷

def maxdrop(p):
  high = low = drop = newhigh = 0
  for i in range(len(p)):
    if p[i] >= p[high]:
      newhigh = i # invariant: p[high] <= p[newhigh]
    else: # so: p[i] < p[high] <= p[newhigh]
      newdrop = p[newhigh] - p[i]
      if newdrop >= drop:
        high, low, drop = newhigh, i, newdrop
  return ((high, p[high]), (low, p[low]), drop)
def test():
  p = [20,22,19,20,24,18,21,24,27]
  print p, maxdrop(p)
  p = list(reversed(p))
  print p, maxdrop(p)
  if __name__ == "__main__":
  test()

如果您尝试使用以下列表 [2,1,2,3,4,3,2]

最明显的下降应该发生在4,3,2上 - 最后3个元素。 但是使用我的代码,输出是2,1 - 前2个元素。

请协助,谢谢!

8 个答案:

答案 0 :(得分:5)

您想要最大和的连续序列,但是要反转。 This page对我所看到的内容有最好的解释。

基本算法如下所示:

>>> def min_sum_subsequence(seq):
...     minsofar = 0
...     minendinghere = 0
...     for s in seq:
...         # invariant: maxendinghere and maxsofar are accurate
...         # are accurate up to s
...         minendinghere = min(minendinghere + s, 0)
...         minsofar = min(minsofar, minendinghere)
...     return minsofar
... 
>>> series = [300,301,303,299,300,298,301,305]
>>> returns = [series[i] - series[i-1] for i in range(1, len(series))]
>>> min_sum_subsequence(returns)
-5

您必须添加代码以跟踪开始和结束的索引。

答案 1 :(得分:1)

最好打印所有值并查看结果。

代码的问题在于你写p [i]&gt; p [high]你更新newhigh的值但是high的值没有改变。

只需将其写为p [i]&gt; p [newhigh]并检查它是否给出了正确的结果。我没有检查它是否会给出正确的输出。自己做。

虽然您可以随时使用上述缩短版本。

答案 2 :(得分:0)

Python允许更短的代码:

l = [300,301,303,299,300,298,301,305]

max([(l[i] - l[j], i, j) for i in range(len(l)) for j in range(i, len(l))], key=lambda x:x[0])

(5, 2, 5)

这可能会缩短,但这是一个很好的起点。 另外,正如其他人所说,如果合适,请使用[家庭作业]标签。 编辑:此答案(删除,开始,结束)。

答案 3 :(得分:0)

复制粘贴代码并缩进后,你几乎就在那里。你在哪里测试:

if p[i] >= p[high]:

你不是认为p [i]可能是&gt; = p [high],但是不到p [newhigh]。

答案 4 :(得分:0)

您要求的是最大的非单调递减序列。 this question中有一个类似的单调问题。有很多方法可以解决这个问题。这是一种递归方法。

def biggest_drop(sequence):
    seq_min, seq_max = min(sequence), max(sequence)
    imin, imax = sequence.index(seq_min), sequence.index(seq_max)
    if imin == imax:
        return None
    if imin < imax:
        # split the sequence and look for local drops
        drop_a = biggest_drop(sequence[:imax])
        drop_b = biggest_drop(sequence[imax:])
        if drop_a is None or drop_b is None:
            if drop_a:
                return drop_a
            return drop_b
        value_a = drop_a[0] - drop_a[-1] 
        value_b = drop_b[0] - drop_b[-1]
        if value_a > value_b:
            return drop_a
        else:
            return drop_b
    return sequence[imax:imin+1]

答案 5 :(得分:0)

这是我的解决方案:

start_=stop_=None
min_=0
for start in range(len(li)-1):
    for stop in range(start+1, len(li)):
        tmp= li[stop]-li[start]
        if tmp<min_:
            min_=tmp
            start_=start
            stop_=stop
print min_
print (start_, stop_)

适用于您的样本。

答案 6 :(得分:0)

这是我的尝试。它适用于您提供的所有示例。

我基本上只是通过数组,当两点之间有一个下降时,将第一个点称为A,向前看直到有一个高于A的值。我跟踪该区域的最小值。如果A和最小值之间的差异比我已经找到的更大,我坚持下去。然后我再次开始寻找两点之间的下降,从下一个点开始,高于A

这是代码。它不是非常Python,但它的效果非常好(如果我需要它更快的话,我会去Cython)。此外,它返回下降的幅度。

def maxdrop(p):
    bestdrop = 0
    wheredrop = -1,-1
    i = 0
    while i < len(p) - 1:
        if p[i+1] < p[i]:
            bestlocal = p[i+1]
            wherelocal = i+1
            j = i + 1
            while j < len(p) - 1 and p[j + 1] < p[i]:
                j += 1
                if p[j] < bestlocal:
                    bestlocal = p[j]
                    wherelocal = j
            if p[i] - bestlocal > bestdrop:
                bestdrop = p[i] - bestlocal
                wheredrop = i, wherelocal
            i = j+1
        else:
            i += 1
    return bestdrop,wheredrop

您的代码存在的一个大问题是,只有在找到新的高值后,才会查看下一个最大下降值。

答案 7 :(得分:0)

有一种比这个例子更快的计算mins的方法,但这简洁易读:

>>> data = [300, 301, 303, 299, 300, 298, 301, 305]
>>> mins = [min(data[i:]) for (i, _) in enumerate(data)]
>>> mins
[298, 298, 298, 298, 298, 298, 301, 305]
>>> drops = [ d - m for (d, m) in zip(data, mins)]
>>> drops
[2, 3, 5, 1, 2, 0, 0, 0]
>>> [ (i, data[i] - drop) for (i, drop) in enumerate(drops) if drop == max(drops) ]
[(2, 298)]

知道期间的开始是2而低点是298,期末是:

>>> [ i for (i, x) in enumerate(data) if i > 2 and x == 298]
[5]