微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

k个图之间的最长公共路径

如何解决k个图之间的最长公共路径

我正在查看面试问题并遇到了这个问题,但未能找到可靠的解决方案。

实际问题是在 Leetcode discussion 上提出的。

给定多个学童以及他们从学校到家的路径,找出最长最常见的路径(路径按孩子走的步骤顺序给出)。

示例:

child1 : a -> g -> c -> b -> e
child2 : f -> g -> c -> b -> u
child3 : h -> g -> c -> b -> x

result = g -> c -> b

注意:可以有多个child。输入的形式是steps和childID。例如输入看起来像这样:

(child1,a)
(child2,f)
(child1,g)
(child3,h)
(child1,c)
...

一些建议的最长公共子串可以工作,但它不会示例 -

1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g
1 and 2 will give abc,3 and 4 give pfg
Now ans will be none but ans is fg

这就像图问题,我们如何找到k个图之间的最长公共路径?

解决方法

方法一:用图构建

考虑这个例子:

1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g

绘制有向加权图。

enter image description here

我是个懒惰的人。所以,我没有画出方向箭头,但相信它们是无形的。如果箭头上没有标记,边权重为 1。

给出链中每条边的最大边权重为 MEW 的最长链的长度。

  • MEW 是 4,我们的答案是 FG。
  • 假设 AB 和 BC 的边权重为 4,那么答案应该是 ABC。

下面的例子是 MEW

1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-h
4 m-x-o-p-f-i

如果某个孩子像我一样,他会在回家之前不停地漫游多个地方。在这种情况下,您可能会看到 MEW > #children 并且解决方案会变得复杂。我希望我们输入的所有孩子都听话,他们直接从学校回家。

enter image description here


方法 2:无图构建

如果幸运的是问题提到最长的公共路径应该出现在所有孩子的路径中,即严格 MEW == #children 那么你可以通过更简单的方法解决。下面的图片应该会告诉你该怎么做。

enter image description here

以下面的例子

1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g

方法一:

获取前两个的最长公共图:a-b-c,f-g(结果 1)

获取最后两个最长公共图:p-f-g(结果 2)

使用结果 1 和 2 我们得到:f-g(最终结果)

方法二:

获取前两个的最长公共图:a-b-c,f-g(结果 1)

取结果 1 和下一个图,即 m-n-o-p-f-g:f-g(结果 2)

取结果 2 和下一个图,即 m-x-o-p-f-g:f-g(最终结果)

没有图构建的方法的美妙之处在于,即使孩子们多次漫游相同的路径,我们也能得到正确的解决方案。


如果你提前一步,你可以结合这些方法并使用方法 1 作为方法 2 中的子程序。

,

您可以构建一个有向图 g,当且仅当它存在于所有单独的路径中时,边存在边 a->b,然后删除所有度为零的节点。

  • g 将没有环。如果是这样,那么所有单独的路径中都将存在相同的循环,并且根据定义,路径没有循环。

  • 此外,所有入度和出度都为零或一。例如,如果节点 a 的入度大于 1,则将有两条边代表从两个不同节点到达 a 的两个学生。这样的边不能通过构造出现在 g 中。

该图看起来像一个不连贯的路径集合。可能有多个最大长度的路径,也可能没有(如果您愿意,可以使用空路径)。

在下面的 Python 代码中,我找到了所有常见的路径并返回一个最大长度的路径。我相信整个过程在输入边的数量上是线性的。


import networkx as nx

path_data = """1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g"""
paths = [line.split(" ")[1].split("-") for line in path_data.split("\n")]
num_paths = len(paths)

# graph h will include all input edges
# edge weight corresponds to the number of students
# traversing that edge
h = nx.DiGraph()
for path in paths:
  for (i,j) in zip(path,path[1:]):
    if h.has_edge(i,j):
      h[i][j]["weight"] += 1
    else:
      h.add_edge(i,j,weight=1)

# graph g will only contain edges traversed by all students
g = nx.DiGraph()
g.add_edges_from((i,j) for i,j in h.edges if h[i][j]["weight"] == num_paths)

def longest_path(g):
  # assumes g is a disjoint collection of paths
  all_paths = list()
  for node in g.nodes:
    path = list()
    if g.in_degree[node] == 0:
      while True:
        path.append(node)
        try:
          node = next(iter(g[node]))
        except:
          break
    all_paths.append(path)
  if not all_paths:
    # handle the "empty path" case
    return []
  return max(all_paths,key=len)

print(longest_path(g))
# ['f','g']

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。