Python 终止重叠指数的迭代解法
我有一个列表,其中包含表示数字范围的元组。我的目标是返回该集合的所有可能子集(请参见下面的注释;真正寻找最长的子集),这些子集在每个元组中仅重叠第二个值,或者根本不重叠。我一直使用的函数是这个问题的递归解决方案Python 终止重叠指数的迭代解法,python,list,loops,recursion,iteration,Python,List,Loops,Recursion,Iteration,我有一个列表,其中包含表示数字范围的元组。我的目标是返回该集合的所有可能子集(请参见下面的注释;真正寻找最长的子集),这些子集在每个元组中仅重叠第二个值,或者根本不重叠。我一直使用的函数是这个问题的递归解决方案 def get_all_end_overlapping_indices(lst, i, out): all_possibilities = [] def _get_all_end_overlapping_indices_helper(list_in, i, out):
def get_all_end_overlapping_indices(lst, i, out):
all_possibilities = []
def _get_all_end_overlapping_indices_helper(list_in, i, out):
r = -1
if i == len(list_in):
if out:
if len(all_possibilities) == 0:
all_possibilities.append(out)
else:
all_possibilities.append(out)
return
n = i + 1
while n < len(list_in) and r > list_in[n][0]:
n += 1
_get_all_end_overlapping_indices_helper(list_in, n, out)
r = list_in[i][1]
n = i + 1
while n < len(list_in) and r > list_in[n][0]:
n += 1
_get_all_end_overlapping_indices_helper(list_in, n, out + [list_in[i]])
_get_all_end_overlapping_indices_helper.count = 0
lst.sort()
_get_all_end_overlapping_indices_helper(list_in = lst, i = 0, out = [])
return all_possibilities
由于我最终将处理更大的元组集合(而且运行速度非常慢),我想实现一个迭代解决方案;不幸的是,我被难倒了。此代码段最初来自:。虽然它能工作,但我发现破解它的工作原理很难。有人能提供一些关于如何构造这个问题的迭代解决方案的提示吗
注意:我实际上只希望获得最长的输出(见下文)。我总是可以在以后过滤掉那些较短的(也就是说,那些位于最长的内部的),但是如果这样做更容易的话,我可以很乐意地去掉它们
[(0.0, 2.0), (4.0, 5.5), (6.0, 7.25)]
[(0.0, 2.0), (2.5, 4.5), (6.0, 7.25)]
[(0.0, 2.0), (2.0, 5.75), (6.0, 7.25)]
[(0.0, 2.0), (2.0, 4.0), (4.0, 5.5), (6.0, 7.25)]
[(0.0, 4.0), (4.0, 5.5), (6.0, 7.25)]
编辑我以前的回答并没有真正回答这个问题,因此这里有一段代码可以真正回答这个问题 我们需要找到的是非重叠元组序列的帕累托最优前沿(包含意义上的帕累托最优)
- 首先,我们需要找到“源”元组,也就是可以位于元组序列开头的元组
- 然后,我们可以计算每个元组的“后继元组”列表
[(0.0,2.0)、(0.0,4.0)、(2.5,4.5)、(2.0,5.75)、(2.0,4.0)、(6.0,7.25)、(4.0,5.5)]
输出: 我认为这个问题在多项式时间内是不可解的,因为输出的大小可能是输入大小的指数。然而,它将运行得相当快,因为构建这4个字典需要
O(n²)
,然后每个路径都以线性时间w.r.t其长度输出
编辑结束,下面是旧解决方案
我们可以在多项式时间内解决这个问题,把它归结为DAG(有向无环图)中的最长路径问题
首先,我们需要将问题建模为DAG。每个元组代表一个顶点,我们从
(a,b)
到(c,d)
当且仅当b非常感谢,@m.raynal!这对我很有帮助。使用此框架,是否可以检索DAG中不重叠的其他路径?在我的帖子中,您可能会看到(在底部),我希望检索所有(最长的)非重叠路径,如[(0.0,2.0),(2.5,4.5),(6.0,7.25)]和[(0.0,2.0),(4.0,5.5),(6.0,7.25)]。您好,使用这个框架,可以找到最长路径的帕累托最优边界。但是今天早上我一直在思考你的问题,我在这个框架之外想出了一个更简单、更好的解决方案,今晚我会发布。@Lukeppeppel你可以看看新的解决方案,我想这是你这次的问题的答案:-)非常感谢你编辑的答案。这正是我想要的!:-)
[(0.0, 2.0), (4.0, 5.5), (6.0, 7.25)]
[(0.0, 2.0), (2.5, 4.5), (6.0, 7.25)]
[(0.0, 2.0), (2.0, 5.75), (6.0, 7.25)]
[(0.0, 2.0), (2.0, 4.0), (4.0, 5.5), (6.0, 7.25)]
[(0.0, 4.0), (4.0, 5.5), (6.0, 7.25)]
sources = {
(a, b)
for (a, b) in tup_lst
if not any(d <= a for (c, d) in tup_lst)
}
sinks = {
(a, b)
for (a, b) in tup_lst
if not any(b <= c for (c, d) in tup_lst)
}
min_successor = {
(a, b): min(d for c, d in tup_lst if c >= b)
for (a, b) in set(tup_lst) - sinks
}
successors = {
(a, b): [
(c, d)
for (c, d) in tup_lst
if b <= c <= d and c < min_successor[(a, b)]
] for (a, b) in tup_lst
}
def print_path_rec(node, path):
if node in sinks:
print(path + [node])
else:
for successor in successors[node]:
print_path_rec(successor, path + [node])
for source in sources:
print_path_rec(source, [])
[(0.0, 2.0), (2.5, 4.5), (6.0, 7.25)]
[(0.0, 2.0), (2.0, 5.75), (6.0, 7.25)]
[(0.0, 2.0), (2.0, 4.0), (4.0, 5.5), (6.0, 7.25)]
[(0.0, 4.0), (4.0, 5.5), (6.0, 7.25)]
def overlap_condition(tup1, tup2):
if tup1 == tup2:
return False
a, b = tup1
c, d = tup2
return b <= c
def adj_mat_from_tup_list(tup_lst):
return [
[
1 if overlap_condition(tup_lst[i], tup_lst[j]) else 0
for j in range(len(tup_lst))
] for i in range(len(tup_lst))
]
def topological_sort(adj_mat):
sorted_v = []
sinks = {
i for i in range(len(adj_mat))
if not any(adj_mat[j][i] == 1 for j in range(len(adj_mat)))
}
while sinks:
v = sinks.pop()
sorted_v += [v]
for j in range(len(adj_mat)):
if adj_mat[v][j] == 1:
adj_mat[v][j] = 0
if not any(adj_mat[w][j] for w in range(len(adj_mat))):
sinks.add(j)
return sorted_v
def get_longest_path(adj_mat, sorted_v):
dists = {v: 0 for v in range(len(adj_mat))}
preds = {v: None for v in range(len(adj_mat))}
for v in sorted_v:
for u in range(len(adj_mat)):
if adj_mat[u][v]:
dists[v] = max(dists[v], dists[u] + 1)
preds[v] = u
current_v = {
v for v in range(len(adj_mat))
if dists[v] == max(dists.values())
}.pop()
result = [current_v]
while preds[current_v] is not None:
current_v = preds[current_v]
result += [current_v]
return result[::-1]
def get_all_end_overlap_tups(tup_lst):
sorted_v = topological_sort(adj_mat_from_tup_list(tup_lst))
adj_mat = adj_mat_from_tup_list(tup_lst)
return [tup_lst[i] for i in get_longest_path(adj_mat, sorted_v)]
lst = [
(0.0, 2.0), (0.0, 4.0), (2.5, 4.5), (2.0, 5.75),
(2.0, 4.0), (6.0, 7.25), (4.0, 5.5)
]
print(get_all_end_overlap_tups(lst))