这里是基于izomorphius上面非常有帮助的提示的Python实现。它建立在增长子序列问题的此实现之上。正如izomorphius所说,它通过跟踪“到目前为止找到的最佳V”以及“到目前为止找到的最佳递增序列”来工作。请注意,一旦确定了V,将其扩展与扩展递减序列没有区别。此外,必须有一个规则从先前找到的递增子序列中“生成”新的候选V。
from bisect import bisect_left
def Vsequence(seq):
"""Returns the longest (non-contiguous) subsequence of seq that
first increases, then decreases (i.e. a "V sequence").
"""
head = [0]
head_v = []
predecessor = [-1] * len(seq)
predecessor_v = [-1] * len(seq)
for i in xrange(1, len(seq)):
j = -1
if len(head_v) > 0:
j = bisect_left([-seq[head_v[idx]] for idx in xrange(len(head_v))], -seq[i])
if j == len(head_v):
head_v.append(i)
if seq[i] > seq[head_v[j]]:
head_v[j] = i
k = -1
if len(head) > 1 and seq[i] < seq[head[-1]]:
k = len(head)
extend_with(head_v, i, k + 1)
for idx in range(k,-1,-1):
if seq[head_v[idx]] > seq[i]: break
head_v[idx] = i
if k > j:
predecessor_v[i] = head[-1]
trace_idx = predecessor_v[i]
while trace_idx > -1:
predecessor_v[trace_idx] = predecessor[trace_idx]
trace_idx=predecessor_v[trace_idx]
elif j > 0:
predecessor_v[i] = head_v[j - 1]
j = bisect_left([seq[head[idx]] for idx in xrange(len(head))], seq[i])
if j == len(head):
head.append(i)
if seq[i] < seq[head[j]]:
head[j] = i
if j > 0: predecessor[i] = head[j - 1]
result = []
trace_idx = head_v[-1]
while (trace_idx >= 0):
result.append(seq[trace_idx])
trace_idx = predecessor_v[trace_idx]
return result[::-1]
一些示例输出:
>>> l1
[26, 92, 36, 61, 91, 93, 98, 58, 75, 48, 8, 10, 58, 7, 95]
>>> Vsequence(l1)
[26, 36, 61, 91, 93, 98, 75, 48, 10, 7]
>>>
>>> l2
[20, 66, 53, 4, 52, 30, 21, 67, 16, 48, 99, 90, 30, 85, 34, 60, 15, 30, 61, 4]
>>> Vsequence(l2)
[4, 16, 48, 99, 90, 85, 60, 30, 4]