我發現了很多查找列表交集的方法,但我在查找訂單時找到找到交集的有效方法時遇到了問題。查找兩個列表的重疊,保留序列的順序
list1 = [1, 2, 3, 4, 5, 6, 7]
list2 = [7, 6, 3, 4, 5, 8]
函數應該返回[3, 4, 5]
我已經知道了,只有一個重疊的順序,我就知道它的最小長度,而不是它的確切長度。
我發現了很多查找列表交集的方法,但我在查找訂單時找到找到交集的有效方法時遇到了問題。查找兩個列表的重疊,保留序列的順序
list1 = [1, 2, 3, 4, 5, 6, 7]
list2 = [7, 6, 3, 4, 5, 8]
函數應該返回[3, 4, 5]
我已經知道了,只有一個重疊的順序,我就知道它的最小長度,而不是它的確切長度。
您正在尋找Longest Common Subsequence算法;以下使用動態編程來發現在O(NM)中的元素的時間(長度爲N和M序列):
def lcs(a, b):
tbl = [[0 for _ in range(len(b) + 1)] for _ in range(len(a) + 1)]
for i, x in enumerate(a):
for j, y in enumerate(b):
tbl[i + 1][j + 1] = tbl[i][j] + 1 if x == y else max(
tbl[i + 1][j], tbl[i][j + 1])
res = []
i, j = len(a), len(b)
while i and j:
if tbl[i][j] == tbl[i - 1][j]:
i -= 1
elif tbl[i][j] == tbl[i][j - 1]:
j -= 1
else:
res.append(a[i - 1])
i -= 1
j -= 1
return res[::-1]
演示:
>>> def lcs(a, b):
... tbl = [[0 for _ in range(len(b) + 1)] for _ in range(len(a) + 1)]
... for i, x in enumerate(a):
... for j, y in enumerate(b):
... tbl[i + 1][j + 1] = tbl[i][j] + 1 if x == y else max(
... tbl[i + 1][j], tbl[i][j + 1])
... res = []
... i, j = len(a), len(b)
... while i and j:
... if tbl[i][j] == tbl[i - 1][j]:
... i -= 1
... elif tbl[i][j] == tbl[i][j - 1]:
... j -= 1
... else:
... res.append(a[i - 1])
... i -= 1
... j -= 1
... return res[::-1]
...
>>> list1 = [1, 2, 3, 4, 5, 6, 7]
>>> list2 = [7, 6, 3, 4, 5, 8]
>>> lcs(list1, list2)
[3, 4, 5]
這將找到的子序列位置無關的和如果其他元素混在其中:
>>> lcs([1, 2, 3, 4, 5, 6, 7], [7, 3, 6, 4, 8, 5])
[3, 4, 5]
如果我已經知道子序列的最小長度,並且只有一個,有什麼辦法比O(MN)算法做得更好? – prooffreader 2014-10-04 22:26:44
@prooffreader:你仍然必須找到這些元素,這意味着你必須掃描這兩個序列。 – 2014-10-04 22:31:22
@prooffreader:這裏的最小長度並不能真正幫到你。知道*最大*長度會讓你在第一階段提前停止搜索,並提前一點移動到第二階段(重建子序列)。 – 2014-10-04 23:43:18
聽起來像[最長的公共子序列](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem)問題給我。 – 2014-10-04 21:36:30
@MartijnPieters,你是對的,現在我知道該怎麼稱呼它了,我發現了一些算法。 – prooffreader 2014-10-04 21:39:28
嗯...我希望通過知道只有一個共同的子序列並且具有最小長度,我可以避免使用O(MN)算法。 – prooffreader 2014-10-04 22:26:00