考虑一系列硬币投掷:1,0,0,1,0,1,其中tail = 0且head = 1.
所需的输出是序列:0,1,2,0,1,0
输出序列的每个元素都计算自上一个头以来的尾部数量。
我尝试过一种天真的方法:
def timer(seq):
if seq[0] == 1: time = [0]
if seq[0] == 0: time = [1]
for x in seq[1:]:
if x == 0: time.append(time[-1] + 1)
if x == 1: time.append(0)
return time
问题:有更好的方法吗?
答案 0 :(得分:5)
使用NumPy:
import numpy as np
seq = np.array([1,0,0,1,0,1,0,0,0,0,1,0])
arr = np.arange(len(seq))
result = arr - np.maximum.accumulate(arr * seq)
print(result)
产量
[0 1 2 0 1 0 1 2 3 4 0 1]
为什么arr - np.maximum.accumulate(arr * seq)
?所需的输出似乎与整数的简单进展有关:
arr = np.arange(len(seq))
所以,自然的问题是,如果seq = np.array([1, 0, 0, 1, 0, 1])
且预期结果是expected = np.array([0, 1, 2, 0, 1, 0])
,那么x
的值是什么
arr + x = expected
由于
In [220]: expected - arr
Out[220]: array([ 0, 0, 0, -3, -3, -5])
看起来x
应该是arr * seq
的累积最大值:
In [234]: arr * seq
Out[234]: array([0, 0, 0, 3, 0, 5])
In [235]: np.maximum.accumulate(arr * seq)
Out[235]: array([0, 0, 0, 3, 3, 5])
答案 1 :(得分:3)
第1步: 反转l
:
In [311]: l = [1, 0, 0, 1, 0, 1]
In [312]: out = [int(not i) for i in l]; out
Out[312]: [0, 1, 1, 0, 1, 0]
第2步: 列出补偿;如果当前值为1,则将先前值添加到当前值。
In [319]: [out[0]] + [x + y if y else y for x, y in zip(out[:-1], out[1:])]
Out[319]: [0, 1, 2, 0, 1, 0]
通过压缩相邻的元素,摆脱了多风的情况。
答案 2 :(得分:3)
>>> a = [1, 0, 0, 1, 0, 1]
>>> b = [1 - x for x in a]
>>> list(accumulate(b, lambda total,e: total+1 if e==1 else 0))
[0, 1, 2, 0, 1, 0]
accumulate
仅在Python 3中定义。但是,如果您想在Python 2中使用它,那么上述文档中的等效Python代码。
需要反转a
,因为accumulate
返回的第一个元素是第一个列表元素,与累加器函数无关:
>>> list(accumulate(a, lambda total,e: 0))
[1, 0, 0, 0, 0, 0]
答案 3 :(得分:1)
所需的输出是一个与输入长度相同的数组,并且所有值都不等于输入。因此,算法必须至少为O(n)才能形成新的输出数组。此外,对于此特定问题,您还需要扫描输入数组的所有值。所有这些操作都是O(n),它不会更有效。常量可能不同,但您的方法已经在O(n)中,并且不会更低。
答案 4 :(得分:0)
使用reduce
:
time = reduce(lambda l, r: l + [(l[-1]+1)*(not r)], seq, [0])[1:]
答案 5 :(得分:0)
我尝试在以下代码中清楚,并且与使用显式累加器的原始代码不同。
>>> s = [1,0,0,1,0,1,0,0,0,0,1,0]
>>> def zero_run_length_or_zero(seq):
"Return the run length of zeroes so far in the sequnece or zero"
accumulator, answer = 0, []
for item in seq:
accumulator = 0 if item == 1 else accumulator + 1
answer.append(accumulator)
return answer
>>> zero_run_length_or_zero(s)
[0, 1, 2, 0, 1, 0, 1, 2, 3, 4, 0, 1]
>>>