我想解决这个问题,但我被困住了。
编写程序,以便在给出价格清单时查找最大价格下降的时间段。例如,如果列表是[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个元素。
请协助,谢谢!
答案 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]