【问题标题】:Python: Sampling indices from a list with constraintsPython:从具有约束的列表中采样索引
【发布时间】:2021-10-11 06:20:35
【问题描述】:

我想知道如何从具有如下约束的列表中采样索引:

               1111
     01234567890123
a = "ABAAABABBBABAB"
b = "ABABBB"

问题是如何找到a的有序采样字符等于b

所以,问题的答案应该如下所示,

[0, 1, 2, 5, 7, 8],
[0, 1, 2, 5, 7, 9],
[0, 1, 2, 5, 7, 11],
...,
[2, 5, 6, 7, 8, 9],
...

因为b 等于a[0] + a[1] + a[2] + a[5] + a[7] + a[8]。 所以[0, 1, 2, 5, 7, 8] 是问题的一个答案。 但是答案的指标应该满足有序的条件。 不能是[2, 1, 3, 5, 7, 8]a[2] + a[1] + a[3] + a[5] + a[7] + a[8] 等于b,但不能满足有序状态条件。

a 的长度为 22,b 的长度总是小于a 的长度。

我实施了蛮力解决这个问题,但它需要很大的时间复杂度。

有没有比蛮力更好的算法? 如果有,应该如何实现?

【问题讨论】:

  • 请出示您已经编写的代码。那里可能有一个简单的错误
  • 可以只生成一个列表,例如[0, 1, 2, 5, 7, 8],还是需要一种算法来生成所有可能的索引列表以从 a 构建 b?
  • @Stef 我需要所有可能的索引列表

标签: python algorithm


【解决方案1】:

如果我理解正确,这是一个global sequence alignment 问题,您可以使用BioPython 来解决:

from Bio import pairwise2

a = "ABAAABABBBABAB"
b = "ABABBB"

for alignment in pairwise2.align.globalxx(a, b):
    positions = [i for i, v in enumerate(alignment.seqB) if v != "-"]
    print(positions)

输出 (部分)

[0, 1, 6, 7, 8, 13]
[0, 1, 4, 7, 8, 13]
[0, 1, 3, 7, 8, 13]
[0, 1, 2, 7, 8, 13]
[0, 1, 4, 5, 8, 13]
[0, 1, 3, 5, 8, 13]
[0, 1, 2, 5, 8, 13]
[0, 1, 4, 5, 7, 13]
[0, 1, 3, 5, 7, 13]
[0, 1, 2, 5, 7, 13]

【讨论】:

  • 我试过了,看来pairwise2.align.globalxx(a, b) 生成的对齐数上限为 256?
  • @Stef 我认为上限为 1000。
【解决方案2】:

不能在恒定时间内完成,但可以以大致线性的时间复杂度完成(至少,相对于 A - 我认为复杂度的上限是 O(A * B))如下:

def indices(A, B):
    # store partial patterns and complete patterns as we go
    # partial patterns will be stored in a list, where each element
    # is a 2-tuple (next_char_of_B_to_look_for, current_index_list)
    partial_patterns = []
    complete_patterns = []
    for (idx, char) in enumerate(A):
        # look for the next element, for any partial patterns we have
        # if we find it, then mark the index and increment the char to look for
        for p in partial_patterns:
            if p[0] < len(B) and char == B[p[0]]:
                p[1].append(idx)
                p[0] += 1
                # p[0] == len(B) indicates a completed pattern, and also 
                # will stop this `if` from being triggered again for this 
                # now-completed pattern (which will be ignored hereafter)
                if p[0] == len(B):
                    complete_patterns.append(p[1])
        # always look for the first element of B to start a new partial pattern
        if char == B[0]:
            partial_patterns.append([1, [idx]])
    return complete_patterns

a = "ABAAABABBBABAB"
b = "ABABBB"
indices(a, b)
# [[0, 1, 2, 5, 7, 8], 
#  [2, 5, 6, 7, 8, 9], 
#  [3, 5, 6, 7, 8, 9], 
#  [4, 5, 6, 7, 8, 9]]

我相信这是给定输入的正确输出(因为索引 6 是最后一个 A,后面至少有三个 Bs)

【讨论】:

  • 我非常确信通过同时在两个字符串上前进,贪心算法将是 O(A+B) = O(A)。如果你最终得到一个与 A*B 成比例的复杂度,那么你一定是在做一些不寻常的事情。
  • @Stef 我说A * B 因为考虑了多个索引列表
  • 噢噢噢,你想生成所有个可能的索引列表吗?我认为 OP 只是要求制作一份清单。
  • 但在这种情况下,复杂性可能比简单的 A*B 差得多;例如,假设对于某些整数 k 和 n,我们设置 b = "ab" * k = "abab...ab"a = ("a"*n+"b"*n)*k = "aaaabbbbaaaabbbb...aaaabbbb"。然后是len(b) == 2*klen(a) = 2*n*k,但可能的解决方案数量比n**k 多。例如,如果 n 是固定的并且 k 趋于无穷大,那么复杂度在 len(a) 中是指数级的,这比 O(len(a)*len(b)) 差得多。
【解决方案3】:

建立一个类似于Longest common subsequence problem的表,然后使用Reading out all LCSs部分提取所有LCS(这里LCS是B序列)

【讨论】:

    【解决方案4】:

    简单的解决方案是:

    a = "ABAAABABBBABAB"
    b = "ABABBB"
    
    total_res = []
    def find_indices(index):
        b_index = 0
        res = []
        for c in range(index, len(a)):
            if b_index > len(b) - 1:
                break
            if a[c] == b[b_index]:
                res.append(c)
                b_index += 1
        if res not in total_res and res:
            print(res)
            total_res.append(res)
    for c in range(len(a)):
        find_indices(c)
    

    输出:

    [0, 1, 2, 5, 7, 8]
    [2, 5, 6, 7, 8, 9]
    [3, 5, 6, 7, 8, 9]
    [4, 5, 6, 7, 8, 9]
    [6, 7, 10, 11, 13]
    [10, 11, 12, 13]
    [12, 13]
    

    【讨论】:

    • 为什么要打扰a_lst, b_lst = list(a), list(b)?字符串已经是可迭代的并且可以被索引和加长,这似乎没有任何目的
    • @GreenCloakGuy 正确,谢谢。
    猜你喜欢
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 1970-01-01
    相关资源
    最近更新 更多