英文:
Find longest subsequence in a list
问题
我想编写一个在线性时间内找到列表中最长升序序列的函数。这似乎是一个非常简单的任务,但是没有嵌套的for循环,我有些卡住。我的想法如下:
if len(L) == 0 or len(L) == 1:
return len(L)
if all(L[i] == L[0] for i in range(len(L)-1)):
return len(L)
left = [1] * len(L)
right = [1] * len(L)
count = 1
for i in range(len(L)-1):
if L[i] <= L[i+1]:
count += 1
left[i+1] = count
else:
count = 1
left[i+1] = count
count = 1
for i in range(len(L)-1, -1, -1):
if L[i] <= L[i-1]:
count += 1
right[i-1] = count
else:
count = 1
right[i-1] = count
idx_left = left.index(max(left))
idx_right = right.index(max(right))
if max(max(left), max(right)) == max(left) and idx_left == len(left) - 1:
return max(left)
请注意,这是您提供的代码的翻译部分。如果您有任何其他问题或需要进一步的解释,请随时告诉我。
英文:
I want to write a function that finds the longest ascending sequence in a list in linear time. This seems like a really easy task but without nested for-loops I am stuck somehow. My idea was the following:
if len(L) == 0 or len(L) == 1:
return len(L)
if all(L[i] == L[0] for i in range(len(L)-1)):
return len(L)
left = [1] * len(L)
right = [1] * len(L)
count = 1
for i in range(len(L)-1):
if L[i] <= L[i+1]:
count += 1
left[i+1] = count
else:
count = 1
left[i+1] = count
count = 1
for i in range(len(L)-1, -1, -1):
if L[i] <= L[i-1]:
count += 1
right[i-1] = count
else:
count = 1
right[i-1] = count
idx_left = left.index(max(left))
idx_right = right.index(max(right))
if max(max(left), max(right)) == max(left) and idx_left == len(left) - 1:
return max(left)
答案1
得分: 1
你可以尝试这样做:
mylist=[10,9,8,10,6,5,4,3,2,3]
previous = mylist[0]
max_sublist = [previous]
current_sublist = [previous]
increasing = True
for x in mylist[1:]:
if increasing and previous <= x:
current_sublist.append(x)
elif previous >= x:
increasing = False
current_sublist.append(x)
else:
if len(current_sublist) > len(max_sublist):
max_sublist = current_sublist[:]
current_sublist = [previous, x]
increasing = True
previous = x
if len(current_sublist) > len(max_sublist):
max_sublist = current_sublist[:]
print(f"{max_sublist=}\n{len(max_sublist)=}")
英文:
You can try this:
mylist=[10,9,8,10,6,5,4,3,2,3]
previous = mylist[0]
max_sublist = [previous]
current_sublist = [previous]
increasing = True
for x in mylist[1:]:
if increasing and previous <= x:
current_sublist.append(x)
elif previous >= x:
increasing = False
current_sublist.append(x)
else:
if len(current_sublist) > len(max_sublist):
max_sublist = current_sublist[:]
current_sublist = [previous, x]
increasing = True
previous = x
if len(current_sublist) > len(max_sublist):
max_sublist = current_sublist[:]
print(f"{max_sublist=}\n{len(max_sublist)=}")
It gives:
max_sublist=[8, 10, 6, 5, 4, 3, 2]
len(max_sublist)=7
答案2
得分: 1
尝试处理两个值之间的差异,我不确定它适用于每种情况,但这是一个O(n)的开始,
最终在结果中加1,因为它在计算比较次数时,最后一个值不会被计算。
def sequence(seq):
max_len = 0
current_len = 0
going_down = False
for i in range(len(seq)-1):
if seq[i] == seq[i+1]:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
if seq[i] < seq[i+1]:
if going_down:
current_len = 1
going_down = False
continue
else:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
if seq[i] > seq[i+1]:
if going_down:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
else:
going_down = True
current_len += 1
if max_len < current_len:
max_len = current_len
return max_len + 1
[10, 9, 8, 10, 6, 5, 4, 3, 2, 3] # 7
[4, 5, 3, 2, 1, 3, 6, 4, 7] # 5
[10, 9, 8, 7, 6, 5, 4, 3, 2, 3] # 9
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 19
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 10
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 9
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1] # 9
[1, 1, 1, 0, 0, 0, 0, 0, 0, 2] # 9
英文:
try working on the diffrences between 2 values,
I'm not sure it works for every case but it's a start in o(n),
added 1 to the resault in the end cause it's counting comparisons so the last value will not be counted
def sequance(seq):
max_len = 0
current_len = 0
going_down = False
for i in range(len(seq)-1):
if seq[i] == seq[i+1]:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
if seq[i] < seq[i+1]:
if going_down:
current_len = 1
going_down = False
continue
else:
current_len +=1
if max_len < current_len:
max_len = current_len
continue
if seq[i] > seq[i+1]:
if going_down:
current_len += 1
if max_len < current_len:
max_len = current_len
continue
else:
going_down = True
current_len += 1
if max_len < current_len:
max_len = current_len
return max_len + 1
[10, 9, 8, 10, 6, 5, 4, 3, 2, 3] # 7
[4, 5, 3, 2, 1, 3, 6, 4, 7] # 5
[10, 9, 8, 7, 6, 5, 4, 3, 2, 3] # 9
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 19
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 10
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 9
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1] # 9
[1, 1, 1, 0, 0, 0, 0, 0, 0, 2] # 9
答案3
得分: 1
你可以考虑分组相同值的增加/减少状态,并跟踪前一个长度。该算法的复杂度是O(n),只需一次输入遍历:
from itertools import groupby
def sequence(lst):
max_len = 0
prev = float('nan')
prev_len = 0
running_len = 0
increasing = False
for k, g in groupby(lst):
L = len(list(g))
if k < prev:
running_len += L
increasing = False
else:
if increasing:
running_len += L
else:
max_len = max(max_len, running_len)
running_len = L + prev_len
increasing = True
prev = k
prev_len = L
return max(max_len, running_len)
sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])
输出: 7
注意: itertools.groupby
只是一种方便的方法,用于避免处理连续相同的值。但你不必使用它,可以自己跟踪这些值。
其他示例:
sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])
# 7 * * * * * * *
sequence([4, 5, 3, 2, 1, 3, 6, 4, 7])
# 5 * * * * *
sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 3])
# 9 * * * * * * * * *
sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
# 10 * * * * * * * * * *
sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 10 * * * * * * * * * *
sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
# 19 * * * * * * * * * * * * * * * * * * *
sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
# 10 * * * * * * * * * *
sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
# 10 * * * * * * * * * *
sequence([1, 0, 0, 0, 0, 0, 0, 0, 0, 1])
# 9 * * * * * * * * *
sequence([1, 1, 0, 0, 0, 0, 0, 0, 0, 1])
# 9 * * * * * * * * *
sequence([1, 1, 1, 0, 0, 0, 0, 0, 0, 2])
# 9 * * * * * * * * *
重构代码
这是与上面相同的逻辑,但进行了代码重构,测试已合并,中间变量已删除等。
from itertools import groupby
def sequence(lst):
max_len = prev_len = running_len = 0
prev = float('nan')
decreasing = False
for k, g in groupby(lst):
if k < prev:
decreasing = True
elif decreasing:
max_len = max(max_len, running_len)
running_len = prev_len
decreasing = False
prev = k
prev_len = len(list(g))
running_len += prev_len
return max(max_len, running_len)
英文:
You can consider the increasing/decreasing state of grouped identical values, and keep track of the previous length. The complexity is O(n) with a single pass on the input:
from itertools import groupby
def sequence(lst):
max_len = 0
prev = float('nan')
prev_len = 0
running_len = 0
increasing = False
for k, g in groupby(lst):
L = len(list(g))
if k < prev:
running_len += L
increasing = False
else:
if increasing:
running_len += L
else:
max_len = max(max_len, running_len)
running_len = L + prev_len
increasing = True
prev = k
prev_len = L
return max(max_len, running_len)
sequence([10,9,8,10,6,5,4,3,2,3])
Output: 7
NB. itertools.groupby
is just a convenience to avoid having to handle the successive identical values. But you don't have to use it and can track those yourself.
Other examples:
sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])
#7 * * * * * * *
sequence([4, 5, 3, 2, 1, 3, 6, 4, 7])
#5 * * * * *
sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 3])
#9 * * * * * * * * *
sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
#10 * * * * * * * * * *
sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
#10 * * * * * * * * * *
sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
#19 * * * * * * * * * * * * * * * * * * *
sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
#10 * * * * * * * * * *
sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
#10 * * * * * * * * * *
sequence([1, 0, 0, 0, 0, 0, 0, 0, 0, 1])
#9 * * * * * * * * *
sequence([1, 1, 0, 0, 0, 0, 0, 0, 0, 1])
#9 * * * * * * * * *
sequence([1, 1, 1, 0, 0, 0, 0, 0, 0, 2])
#9 * * * * * * * * *
refactoring the code
This is the exact same logic as above but tests have been combined, intermediate variables removed, etc.
from itertools import groupby
def sequence(lst):
max_len = prev_len = running_len = 0
prev = float('nan')
decreasing = False
for k, g in groupby(lst):
if k < prev:
decreasing = True
elif decreasing:
max_len = max(max_len, running_len)
running_len = prev_len
decreasing = False
prev = k
prev_len = len(list(g))
running_len += prev_len
return max(max_len, running_len)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论