【问题标题】:Find the longest repeated subsequence of max length N in Python在Python中找到最大长度N的最长重复子序列
【发布时间】:2020-08-28 10:46:08
【问题描述】:

我有一些代表事件顺序的字符串:

s1 = 'A->B->E->D->A->C->B->D'

s2= 'A->B->C->A->B'

s3 = 'A->B->A

在每个字符串中,我想找到最大长度为 N 的所有重复模式。

import itertools

def find_all_comb(event_list,max_events):
    all_combs = []
    for j in range(1,max_events+1):
        all_combs.extend(list(set(['->'.join(x) for x in list(itertools.combinations(event_list,j))])))
    return all_combs

def find_repeating_patterns(x):
    split_events = x.split("->")
    all_combs = find_all_comb(split_events,int(len(x)/2))

    repeating_patterns = []
    for comb in all_combs:
        c_split_event = [p for p in split_events if p in comb]
        if '->'.join(c_split_event).count(comb) > 1:
            repeating_patterns.extend([comb])
    output_list = []
    longest_repeating_patterns = [s for s in repeating_patterns if any(set(s).issuperset(set(i)) and len(s) > len(i) for i in repeating_patterns)]
    while output_list != longest_repeating_patterns:
        if longest_repeating_patterns == []:
            break
        output_list = longest_repeating_patterns.copy()
        longest_repeating_patterns = [s for s in longest_repeating_patterns if any(set(s).issuperset(set(i)) and len(s) > len(i) for i in longest_repeating_patterns)]

return output_list

对于s1,这将返回正确的模式[A,B,D],对于s2,它返回[A,B]。对于s3,它应该返回[A],但它返回一个空列表。这是因为这行:

[s for s in repeating_patterns if any(set(s).issuperset(set(i)) and len(s) > len(i) for i in repeating_patterns)]

这不允许len(s) > len(i)

我怎样才能在这里捕获这两种情况?

【问题讨论】:

  • 要求似乎不清楚,因为[A,B,D] 是一个子集而不是子序列。再说一次,您的代码不会忽略顺序,因此它也不是一个简单的子集。
  • @ekhumoro [A,B,D] 那里的一个aubsequence。
  • 在标题中添加了“重复”一词,希望能把事情弄清楚。
  • 我在帖子的最后一行还有一个更简洁的要求,也应该澄清一下。
  • 这真的是关于集合和序列的吗?不清楚如何。

标签: python combinations subsequence


【解决方案1】:

这里有一个更简单有效的解决方案:

def longest_subsequence(events, limit, sep='->'):
    events = list(enumerate(events.split(sep)))
    output = {}
    seen = {}
    for n in range(limit, 0, -1):
        for combination in itertools.combinations(events, n):
            indexes, key = zip(*combination)
            if key in seen:
                if key not in output and seen[key].isdisjoint(indexes):
                    output[key] = sep.join(key)
            else:
                seen[key] = set(indexes)
        if output:
            break
    return list(output.values())

这首先查看最长的匹配,如果找到则提前终止。它通过保存最后一个匹配的索引并将它们与当前候选进行比较来消除自重叠的重复子序列。

演示:

samples = (
    'A->B->E->D->A->C->B->D',
    'A->B->C->A->B',
    'A->B->A',
    'A->B->E->D->A->C->B->E->D->A',
    'B->B->B->C->C',
    'A->B->A->B->C->C',
    'A',
    '',
    )

for index, sample in enumerate(samples, 1):
    result = longest_subsequence(sample, 4)
    print('(%s) %r\n%s\n' % (index, sample, result))
    

输出:

(1) 'A->B->E->D->A->C->B->D'
['A->B->D']

(2) 'A->B->C->A->B'
['A->B']

(3) 'A->B->A'
['A']

(4) 'A->B->E->D->A->C->B->E->D->A'
['A->B->E->D', 'B->E->D->A']

(5) 'B->B->B->C->C'
['B->C']

(6) 'A->B->A->B->C->C'
['A->B->C']

(7) 'A'
[]

(8) ''
[]

【讨论】:

  • 嗨,当输入 'A->B->A->B->C->C' 作为输入时,它只输出 ['A->B']。所以有些事情没有按预期工作。
  • @kspr 好的 - 这很容易改变(请参阅我更新的答案)。这就是为什么我要求你澄清应该如何处理重叠子序列。你并没有真正这样做,所以我只是添加了B->B->B->C->C 样本并使我的输出与你的匹配。请注意,您当前的解决方案因此对于样本 5 和 6 被破坏(如上面输出中的编号)。
【解决方案2】:

添加一个额外的行,将不是子序列的任何内容添加到output_list 中的任何序列中是一种解决方案。

    import itertools

    def find_all_comb(event_list,max_events):
        all_combs = []
        for j in range(1,max_events+1):
            all_combs.extend(list(set(['->'.join(x) for x in list(itertools.combinations(event_list,j))])))
        return all_combs

    def find_repeating_patterns(x):
        split_events = x.split("->")
        all_combs = find_all_comb(split_events,int(len(x)/2))
        
        repeating_patterns = []
        for comb in all_combs:

            c_split_event = [p for p in split_events if p in comb]
            if '->'.join(c_split_event).count(comb) > 1:
                repeating_patterns.extend([comb])
        output_list = []
        longest_repeating_patterns = [s for s in repeating_patterns if any(set(s).issuperset(set(i)) and len(s) > len(i) for i in repeating_patterns)]
        while output_list != longest_repeating_patterns:
            if longest_repeating_patterns == []:
                break
            output_list = longest_repeating_patterns.copy()
            longest_repeating_patterns = [s for s in longest_repeating_patterns if any(set(s).issuperset(set(i)) and len(s) > len(i) for i in longest_repeating_patterns)]
        output_list.extend([s for s in repeating_patterns if not any(set(i).issuperset(set(s)) for i in output_list)]) <--- ADDED LINE FOR SOLUTION

        return output_list


s1 = A->B->E->D->A->C->B->D
s2 = A->B->C->A->B
s3 = A->B->A

print(find_repeating_patterns(s1))

output: [A->B->D]

print(find_repeating_patterns(s2))

output: [A->B]

print(find_repeating_patterns(s3))

output: [A]

【讨论】:

  • A-&gt;B-&gt;E-&gt;D-&gt;A-&gt;C-&gt;B-&gt;E-&gt;D-&gt;A 的输出应该是什么?您当前的解决方案提供 ['B-&gt;E-&gt;D-&gt;A', 'A-&gt;B-&gt;E-&gt;D'],其中包括 一些 重叠子序列,但不是全部。如果包含所有种可能性,则s1 的正确输出将是['A-&gt;B-&gt;E-&gt;D', 'A-&gt;C-&gt;B-&gt;D'](因为ABECBD 可以使用两次)。
  • 您好,限制是一个事件不能用于两种模式。
  • 不确定您是否仍然感兴趣,但我有一个更简单、更有效的解决方案,可以产生与您相同的输出。
  • 请分享,我肯定还是有兴趣的。
  • 好的 - 我现在已经添加了我的替代解决方案。
猜你喜欢
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
  • 2014-11-12
  • 2017-08-29
  • 1970-01-01
  • 2013-05-19
  • 2020-03-22
  • 2022-01-05
相关资源
最近更新 更多