-->

最长重复(k次)的子(Longest repeated (k times) substring)

2019-08-02 13:22发布

我知道这是一个有点被打的话题,但我已经达到帮助的限制,我可以从什么已经回答得。

这是罗莎琳德项目问题LREP 。 我试图找到一个字符串,最长的K-peated子和我已经提供的后缀树,这是很好的。 我知道,我需要注释后缀表传人叶从每个节点的数字,然后找到节点>=k后裔,终于找到最深的那些节点。 理论明智的,我设置。

我已经得到了很多从以下资源(哎呀,我只能发布2)帮助:

  • 在字符串中查找最长的重复序列
  • 深度优先搜索(蟒蛇)

我可以从根到每个叶子得到的路径,但我无法弄清楚如何预先处理树以这样的方式,我可以从每个节点的后代的数量。 我有一个单独的算法,小序列的作品,但它是在指数的复杂性,因此对于较大的东西,它需要的时间太长。 我知道与DFS我应该能够在复杂的线性执行整个任务。 对于这个算法工作,我需要能够得到一个〜40000长度的字符串中最长的K-泥炭在不到5分钟。

下面是一些示例数据(第一行: sequence ,第二行: k ,后缀表格式: parent child location length ):

CATACATAC$
2
1 2 1 1
1 7 2 1
1 14 3 3
1 17 10 1
2 3 2 4
2 6 10 1
3 4 6 5
3 5 10 1
7 8 3 3
7 11 5 1
8 9 6 5
8 10 10 1
11 12 6 5
11 13 10 1
14 15 6 5
14 16 10 1

从这个输出应该是CATAC

用下面的代码(改LiteratePrograms )我已经能够得到的路径,但它仍然需要在较长的序列很长一段时间来解析出的路径的每个节点。

#authors listed at
#http://en.literateprograms.org/Depth-first_search_(Python)?action=history&offset=20081013235803
class Vertex:
    def __init__(self, data):
        self.data = data
        self.successors = []

def depthFirstSearch(start, isGoal, result):
    if start in result:
        return False

    result.append(start)

    if isGoal(start):
        return True
    for v in start.successors:
        if depthFirstSearch(v, isGoal, result):
            return True

    # No path was found
    result.pop()
    return False

def lrep(seq,reps,tree):
    n = 2 * len(seq) - 1
    v = [Vertex(i) for i in xrange(n)]
    edges = [(int(x[0]),int(x[1])) for x in tree]
    for a, b in edges:
        v[a].successors.append(v[b])

    paths = {}
    for x in v:
        result = []
        paths[x.data] = []
        if depthFirstSearch(v[1], (lambda v: v.data == x.data), result):
            path = [u.data for u in result]
            paths[x.data] = path

我想要做的是前期过程中找到满足该节点树descendants >= k之前发现的深度要求。 我还没有读懂了我如何去计算深度呢。 虽然我想有我一些字典,持续跟踪,然后总结路径的各个节点的深度。

所以,我的第一个最重要的问题是:“我如何预处理树的叶子后裔?”

我的第二不太重要的问题是:“在那之后,我怎么能快速计算深度?”

PS我应该指出,这不是功课或那样的话。 我只是想拓展我的视野与一些计算挑战的生物化学。

Answer 1:

在基本的字符串操作的锻炼; Tibial有趣的问题。 我不记得后缀树了;)但是,正如你已经指出:理论的角度来看,你设置。

如何与进行预处理后裔树叶树?

在维基百科存根到这个话题有点混乱。 你只需要知道,如果你是最外面的非叶节点与n >= k孩子的。 如果您发现从根节点的子这一个整个字符串中,后缀树告诉你,有n可能continuitations。 所以必须有n的地方,在此字符串发生。

在那之后,我怎么能快速计算的深度?

这和很多类似的问题,一个简单的关键概念是做深度优先搜索:在每一个节点,要求他们的价值的子元素和最大的将其退还给家长。 根节点将得到最终结果。

如何计算值的问题是不同的。 在这里,你必须为每个节点3个possiblilitys:

  1. 该节点有没有孩子的。 它的叶节点,其结果是无效的。
  2. 每个孩子返回无效的结果。 它的最后一个非叶节点,结果是零(此节点之后没有更多的字符)。 如果此节点有n孩子的,从根到这个节点的每个边的concated字符串出现n整串倍。 如果我们至少需要k节点和k > n ,结果也是无效的。
  3. 一个或多个叶返回的东西有效。 其结果是最大的返回值加上字符串的长度的附连的边缘到它。

当然,你也必须返回correspondending节点。 否则,你就会知道,最长的重复子有多长,但不是它在哪里。

你应该尝试自己先实现代码。 构建树如果要收集所有必要的信息很简单,但并不容易。 不过这里有一个简单的例子。 请注意:每一个理智检查被退学了,一切都将失败可怕,如果输入的是不知何故无效。 例如,不要尝试使用任何其他根指数大于一个,不给参考,作为父母,这是不是作为一个孩子的前引用等很大的提升空间* 提示节点;)*。

class Node(object):
    def __init__(self, idx):
        self.idx = idx     # not needed but nice for prints 
        self.parent = None # edge to parent or None
        self.childs = []   # list of edges

    def get_deepest(self, k = 2):
        max_value = -1
        max_node = None
        for edge in self.childs:
            r = edge.n2.get_deepest()
            if r is None: continue # leaf
            value, node = r
            value += len(edge.s)
            if value > max_value: # new best result
                max_value = value
                max_node = node
        if max_node is None:
            # we are either a leaf (no edge connected) or 
            # the last non-leaf.
            # The number of childs have to be k to be valid.
            return (0, self) if len(self.childs) == k else None
        else:
            return (max_value, max_node)

    def get_string_to_root(self):
        if self.parent is None: return "" 
        return self.parent.n1.get_string_to_root() + self.parent.s

class Edge(object):
    # creating the edge also sets the correspondending
    # values in the nodes
    def __init__(self, n1, n2, s):
        #print "Edge %d -> %d [ %s]" % (n1.idx, n2.idx, s)
        self.n1, self.n2, self.s = n1, n2, s
        n1.childs.append(self)
        n2.parent = self

nodes = {1 : Node(1)} # root-node
string = sys.stdin.readline()
k = int(sys.stdin.readline())
for line in sys.stdin:
    parent_idx, child_idx, start, length = [int(x) for x in line.split()]
    s = string[start-1:start-1+length]
    # every edge constructs a Node
    nodes[child_idx] = Node(child_idx)
    Edge(nodes[parent_idx], nodes[child_idx], s)

(depth, node) = nodes[1].get_deepest(k)
print node.get_string_to_root()


文章来源: Longest repeated (k times) substring