tl; dr - 下面的代码显示了我希望通过尝试某种不同的方法来改进的算法。
现在很长的解释。
给定一个整数列表,我想找到连续整数的每个序列,它们与序列的原始起点相同或更高。序列也应该比排名较高的连续序列长 你可能很困惑。我来说明一下我的意思。
当我有一个整数列表时,我可以将它展开以表示其范围。例如:
2,1,1,3,3,1
变为
-,-,-,3,3,-
2,-,-,2,2,-
1,1,1,1,1,1
如您所见,每个整数值都在其各自的行中,并且递减的值填充其下方的列。注意,不必在算法中执行上述过程。
我现在想要返回一个级别/行上的每个序列,这些序列/行没有被另一个序列完全覆盖
例如,这里,列表中没有0,这意味着1的基线具有最大长度。其中一个返回值现在为[1,6,5]:1表示序列所包含的数字,6表示序列长度,5表示序列的最终索引。
对于中间一行,我们只有两个。我们来分析吧。这里的第一个序列是开头的单个二。它的返回值为[2,1,0]。然后有两个空白,之后又有两个两个空白。可是等等!不要添加它们!两个人的序列完全由上面的三个人覆盖。实际上,我们已经完成了这一行
在第一行,我们可以添加三个序列:[3,2,4]
最后的输出现在是
[[1,6,5],[2,1,0],[3,2,4]]
为了澄清,这里有几个例子。它们是100%完整和正确的,我已多次检查它们。
[3,3,3,2,1] -> [[1,5,4],[2,4,3],[3,3,2]]
[7,7,3,0,1,2,3] -> [[1,3,6],[2,2,6],[3,3,2],[3,1,6],[7,2,1]]
[0,0,0] -> []
[0,1,0,4,0,1,0] -> [[1,1,1],[4,1,3],[1,1,5]]
我想到了一种相当复杂的方法,它将列表中的值从最高出现次数迭代到1.每当我遇到一个序列时,我会保存它然后将它的所有元素减1。然而,在我做后者之前,我检查序列的起始和结束索引的左侧或右侧的值是否分别低于序列中的数字。例如,在以下情况中也是如此:
[2,4,4,4,1], looking at 3*4
[1,8,8], looking at 2*8
[9,9,9,8], looking at 3*9
[9,7,4], looking at 2*7 (sequence doesn't formally exist as [7,7],
but would be in the results, as described above)
如果是这种情况,那么我会减少序列的所有值以适应周围环境。
让我们通过一个简单的列表运行该过程:
[4,4,2,1,1,3]
我们首先检查四肢。一开始有两个,方便多了!它没有剩下的值,它的右边值是2 ...所以一个小2磅。所以...我们可以愉快地减少列表中的所有元素。但是,在此之前,我们将序列([4,2,1])的值传递给变量。之后,我们读取最高的周围整数值,将其分配给序列的所有元素并获取:
[2,2,2,1,1,3]
啊哈!现在它与右边的2平分了。我们现在需要做的就是检查是否有任何值为3的整数。好吧,huzzah,还有一个小家伙坐在角落里。同样,我们保存序列的值([3,1,5])并为每个元素分配最高的周围整数,恰好是1:
[2,2,2,1,1,1]
再一次。我们返回[2,3,2]。
[1,1,1,1,1,1]
为什么,看起来并不熟悉。我们所要做的就是返回[1,6,5]并在此完成。
最终输出为[[4,2,1],[3,1,5],[2,3,2],[1,6,5]]。
懒得通过更多的例子...这篇文章反正太长了。
是的,我已经有了一些代码。这是:
def ListProcessing(listL, length, freq):
#to detect end of array and not miss out on last sequences
listL.extend([0])
#Iterating over all unique elements that appear in the list from top to
#bottom, leaving out elements under or equal to _length_
for checkNum in reversed(list(set(sorted(listL))-set(range(length)))):
seqLen = 0
#Iterate over list
for index, val in enumerate(listL):
#current element higher than checkNum?
#Yes -> increase counter of the sequence length
if val >= checkNum:
seqLen += 1
#No -> Reset seqLen. If seqLen is high enough, replace sequence with
# sequence of highest neighbouring elements and yield the seq.
else:
if seqLen > freq-1:
newVal = max(val, listL[index-seqLen-1])
listL[index-seqLen:index] = [newVal] * seqLen
yield(checkNum, seqLen, index-1)
seqLen = 0
AFAIK它完全符合我的要求。
如上所述,我的算法已经有效。然而,这种方法似乎有点复杂,我确信有更好的方法。我很想听到另一种方法 目前正在使用array.array模块实现此功能,以使其更快。如果有人想尝试用它来实现自己的方法,我会非常激动。
欢迎未实现的概念/想法!
答案 0 :(得分:3)
这是一个有趣的问题,这是解决它的另一种方法。让我们举个例子,seq = [4, 4, 2, 1, 1, 3, 2]
。请注意,我们可以从返回与您问题中列出的规则之后的最长序列相关联的结果开始。该结果的格式为[min(seq), len(seq), len(seq) - 1]
或[1, 7, 6]
。
现在您知道所有其他有效结果必须只包含大于min(seq)
的值,因此我们可以将seq
拆分为两个子序列,[4, 4, 2]
和[3, 2]
并查看这些子序列中的有效结果。我们可以递归地为每个子序列重复这个分裂过程,直到我们退出子序列。
在代码中看起来像这样:
def recListProcessing(seq, threshold=0, min_len=1):
len_seq = len(seq)
if len_seq < min_len:
return
min_value = min(seq)
if min_value > threshold:
yield (min_value, len_seq, len_seq - 1)
start = 0
while start < len_seq:
try:
end = seq.index(min_value, start)
except ValueError:
end = len_seq
sub_seq = seq[start:end]
for item in recListProcessing(sub_seq, threshold, min_len):
yield (item[0], item[1], item[2] + start)
start = end + 1