找到列表中的最长子序列

huangapple go评论52阅读模式
英文:

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] &lt;= 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] &lt;= 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 &lt;= x:
        current_sublist.append(x)
    elif previous &gt;= x:
        increasing = False
        current_sublist.append(x)
    else:
        if len(current_sublist) &gt; len(max_sublist):
            max_sublist = current_sublist[:]
        current_sublist = [previous, x]
        increasing = True
    previous = x

if len(current_sublist) &gt; len(max_sublist):
            max_sublist = current_sublist[:]

print(f&quot;{max_sublist=}\n{len(max_sublist)=}&quot;)

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 &lt; current_len:
            max_len = current_len
        continue
    if seq[i] &lt; seq[i+1]:
        if going_down:
            current_len = 1
            going_down = False
            continue
        else:
            current_len +=1
            if max_len &lt; current_len:
                max_len = current_len
            continue

    if seq[i] &gt; seq[i+1]:
        if going_down:
            current_len += 1
            if max_len &lt; current_len:
                max_len = current_len
            continue
        else:
            going_down = True
            current_len += 1
            if max_len &lt; 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(&#39;nan&#39;)
    prev_len = 0
    running_len = 0
    increasing = False
    for k, g in groupby(lst):
        L = len(list(g))
        if k &lt; 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(&#39;nan&#39;)
    decreasing = False
    for k, g in groupby(lst):
        if k &lt; 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)

huangapple
  • 本文由 发表于 2023年2月6日 05:40:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75355712.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定