找到列表中的最长子序列

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

Find longest subsequence in a list

问题

我想编写一个在线性时间内找到列表中最长升序序列的函数。这似乎是一个非常简单的任务,但是没有嵌套的for循环,我有些卡住。我的想法如下:

  1. if len(L) == 0 or len(L) == 1:
  2. return len(L)
  3. if all(L[i] == L[0] for i in range(len(L)-1)):
  4. return len(L)
  5. left = [1] * len(L)
  6. right = [1] * len(L)
  7. count = 1
  8. for i in range(len(L)-1):
  9. if L[i] <= L[i+1]:
  10. count += 1
  11. left[i+1] = count
  12. else:
  13. count = 1
  14. left[i+1] = count
  15. count = 1
  16. for i in range(len(L)-1, -1, -1):
  17. if L[i] <= L[i-1]:
  18. count += 1
  19. right[i-1] = count
  20. else:
  21. count = 1
  22. right[i-1] = count
  23. idx_left = left.index(max(left))
  24. idx_right = right.index(max(right))
  25. if max(max(left), max(right)) == max(left) and idx_left == len(left) - 1:
  26. 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:

  1. if len(L) == 0 or len(L) == 1:
  2. return len(L)
  3. if all(L[i] == L[0] for i in range(len(L)-1)):
  4. return len(L)
  5. left = [1] * len(L)
  6. right = [1] * len(L)
  7. count = 1
  8. for i in range(len(L)-1):
  9. if L[i] &lt;= L[i+1]:
  10. count += 1
  11. left[i+1] = count
  12. else:
  13. count = 1
  14. left[i+1] = count
  15. count = 1
  16. for i in range(len(L)-1, -1, -1):
  17. if L[i] &lt;= L[i-1]:
  18. count += 1
  19. right[i-1] = count
  20. else:
  21. count = 1
  22. right[i-1] = count
  23. idx_left = left.index(max(left))
  24. idx_right = right.index(max(right))
  25. if max(max(left), max(right)) == max(left) and idx_left == len(left) - 1:
  26. return max(left)

答案1

得分: 1

你可以尝试这样做:

  1. mylist=[10,9,8,10,6,5,4,3,2,3]
  2. previous = mylist[0]
  3. max_sublist = [previous]
  4. current_sublist = [previous]
  5. increasing = True
  6. for x in mylist[1:]:
  7. if increasing and previous <= x:
  8. current_sublist.append(x)
  9. elif previous >= x:
  10. increasing = False
  11. current_sublist.append(x)
  12. else:
  13. if len(current_sublist) > len(max_sublist):
  14. max_sublist = current_sublist[:]
  15. current_sublist = [previous, x]
  16. increasing = True
  17. previous = x
  18. if len(current_sublist) > len(max_sublist):
  19. max_sublist = current_sublist[:]
  20. print(f"{max_sublist=}\n{len(max_sublist)=}")
英文:

You can try this:

  1. mylist=[10,9,8,10,6,5,4,3,2,3]
  2. previous = mylist[0]
  3. max_sublist = [previous]
  4. current_sublist = [previous]
  5. increasing = True
  6. for x in mylist[1:]:
  7. if increasing and previous &lt;= x:
  8. current_sublist.append(x)
  9. elif previous &gt;= x:
  10. increasing = False
  11. current_sublist.append(x)
  12. else:
  13. if len(current_sublist) &gt; len(max_sublist):
  14. max_sublist = current_sublist[:]
  15. current_sublist = [previous, x]
  16. increasing = True
  17. previous = x
  18. if len(current_sublist) &gt; len(max_sublist):
  19. max_sublist = current_sublist[:]
  20. print(f&quot;{max_sublist=}\n{len(max_sublist)=}&quot;)

It gives:

  1. max_sublist=[8, 10, 6, 5, 4, 3, 2]
  2. len(max_sublist)=7

答案2

得分: 1

尝试处理两个值之间的差异,我不确定它适用于每种情况,但这是一个O(n)的开始,

最终在结果中加1,因为它在计算比较次数时,最后一个值不会被计算。

  1. def sequence(seq):
  2. max_len = 0
  3. current_len = 0
  4. going_down = False
  5. for i in range(len(seq)-1):
  6. if seq[i] == seq[i+1]:
  7. current_len += 1
  8. if max_len < current_len:
  9. max_len = current_len
  10. continue
  11. if seq[i] < seq[i+1]:
  12. if going_down:
  13. current_len = 1
  14. going_down = False
  15. continue
  16. else:
  17. current_len += 1
  18. if max_len < current_len:
  19. max_len = current_len
  20. continue
  21. if seq[i] > seq[i+1]:
  22. if going_down:
  23. current_len += 1
  24. if max_len < current_len:
  25. max_len = current_len
  26. continue
  27. else:
  28. going_down = True
  29. current_len += 1
  30. if max_len < current_len:
  31. max_len = current_len
  32. 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

  1. def sequance(seq):
  2. max_len = 0
  3. current_len = 0
  4. going_down = False
  5. for i in range(len(seq)-1):
  6. if seq[i] == seq[i+1]:
  7. current_len += 1
  8. if max_len &lt; current_len:
  9. max_len = current_len
  10. continue
  11. if seq[i] &lt; seq[i+1]:
  12. if going_down:
  13. current_len = 1
  14. going_down = False
  15. continue
  16. else:
  17. current_len +=1
  18. if max_len &lt; current_len:
  19. max_len = current_len
  20. continue
  21. if seq[i] &gt; seq[i+1]:
  22. if going_down:
  23. current_len += 1
  24. if max_len &lt; current_len:
  25. max_len = current_len
  26. continue
  27. else:
  28. going_down = True
  29. current_len += 1
  30. if max_len &lt; current_len:
  31. max_len = current_len
  32. return max_len + 1
  33. [10, 9, 8, 10, 6, 5, 4, 3, 2, 3] # 7
  34. [4, 5, 3, 2, 1, 3, 6, 4, 7] # 5
  35. [10, 9, 8, 7, 6, 5, 4, 3, 2, 3] # 9
  36. [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 10
  37. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 10
  38. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] # 19
  39. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 10
  40. [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 10
  41. [1, 0, 0, 0, 0, 0, 0, 0, 0, 1] # 9
  42. [1, 1, 0, 0, 0, 0, 0, 0, 0, 1] # 9
  43. [1, 1, 1, 0, 0, 0, 0, 0, 0, 2] # 9

答案3

得分: 1

你可以考虑分组相同值的增加/减少状态,并跟踪前一个长度。该算法的复杂度是O(n),只需一次输入遍历:

  1. from itertools import groupby
  2. def sequence(lst):
  3. max_len = 0
  4. prev = float('nan')
  5. prev_len = 0
  6. running_len = 0
  7. increasing = False
  8. for k, g in groupby(lst):
  9. L = len(list(g))
  10. if k < prev:
  11. running_len += L
  12. increasing = False
  13. else:
  14. if increasing:
  15. running_len += L
  16. else:
  17. max_len = max(max_len, running_len)
  18. running_len = L + prev_len
  19. increasing = True
  20. prev = k
  21. prev_len = L
  22. return max(max_len, running_len)
  23. sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])

输出: 7

注意: itertools.groupby 只是一种方便的方法,用于避免处理连续相同的值。但你不必使用它,可以自己跟踪这些值。

其他示例:

  1. sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])
  2. # 7 * * * * * * *
  3. sequence([4, 5, 3, 2, 1, 3, 6, 4, 7])
  4. # 5 * * * * *
  5. sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 3])
  6. # 9 * * * * * * * * *
  7. sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
  8. # 10 * * * * * * * * * *
  9. sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  10. # 10 * * * * * * * * * *
  11. sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
  12. # 19 * * * * * * * * * * * * * * * * * * *
  13. sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
  14. # 10 * * * * * * * * * *
  15. sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
  16. # 10 * * * * * * * * * *
  17. sequence([1, 0, 0, 0, 0, 0, 0, 0, 0, 1])
  18. # 9 * * * * * * * * *
  19. sequence([1, 1, 0, 0, 0, 0, 0, 0, 0, 1])
  20. # 9 * * * * * * * * *
  21. sequence([1, 1, 1, 0, 0, 0, 0, 0, 0, 2])
  22. # 9 * * * * * * * * *

重构代码

这是与上面相同的逻辑,但进行了代码重构,测试已合并,中间变量已删除等。

  1. from itertools import groupby
  2. def sequence(lst):
  3. max_len = prev_len = running_len = 0
  4. prev = float('nan')
  5. decreasing = False
  6. for k, g in groupby(lst):
  7. if k < prev:
  8. decreasing = True
  9. elif decreasing:
  10. max_len = max(max_len, running_len)
  11. running_len = prev_len
  12. decreasing = False
  13. prev = k
  14. prev_len = len(list(g))
  15. running_len += prev_len
  16. 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:

  1. from itertools import groupby
  2. def sequence(lst):
  3. max_len = 0
  4. prev = float(&#39;nan&#39;)
  5. prev_len = 0
  6. running_len = 0
  7. increasing = False
  8. for k, g in groupby(lst):
  9. L = len(list(g))
  10. if k &lt; prev:
  11. running_len += L
  12. increasing = False
  13. else:
  14. if increasing:
  15. running_len += L
  16. else:
  17. max_len = max(max_len, running_len)
  18. running_len = L + prev_len
  19. increasing = True
  20. prev = k
  21. prev_len = L
  22. return max(max_len, running_len)
  23. 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:

  1. sequence([10, 9, 8, 10, 6, 5, 4, 3, 2, 3])
  2. #7 * * * * * * *
  3. sequence([4, 5, 3, 2, 1, 3, 6, 4, 7])
  4. #5 * * * * *
  5. sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 3])
  6. #9 * * * * * * * * *
  7. sequence([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
  8. #10 * * * * * * * * * *
  9. sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  10. #10 * * * * * * * * * *
  11. sequence([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
  12. #19 * * * * * * * * * * * * * * * * * * *
  13. sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
  14. #10 * * * * * * * * * *
  15. sequence([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
  16. #10 * * * * * * * * * *
  17. sequence([1, 0, 0, 0, 0, 0, 0, 0, 0, 1])
  18. #9 * * * * * * * * *
  19. sequence([1, 1, 0, 0, 0, 0, 0, 0, 0, 1])
  20. #9 * * * * * * * * *
  21. sequence([1, 1, 1, 0, 0, 0, 0, 0, 0, 2])
  22. #9 * * * * * * * * *

refactoring the code

This is the exact same logic as above but tests have been combined, intermediate variables removed, etc.

  1. from itertools import groupby
  2. def sequence(lst):
  3. max_len = prev_len = running_len = 0
  4. prev = float(&#39;nan&#39;)
  5. decreasing = False
  6. for k, g in groupby(lst):
  7. if k &lt; prev:
  8. decreasing = True
  9. elif decreasing:
  10. max_len = max(max_len, running_len)
  11. running_len = prev_len
  12. decreasing = False
  13. prev = k
  14. prev_len = len(list(g))
  15. running_len += prev_len
  16. 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:

确定