从连续跨度列表中获取最深的覆盖站点

时间:2019-05-16 07:33:32

标签: python algorithm range

  

连续跨度是什么样的剂量?

连续跨度由元组(start, end)表示。

例如,(2, 8)指的是一个从2开始并以8结尾的区域。

  

最广泛的覆盖范围是什么意思?

对于跨度列表,例如[(0, 4), (2, 8), (5, 10), (6, 9)],堆积结果将是:

│ 0......4
│    2...........8
│          5.........10
│            6.....9
└────────────────────────
 0 1 2 3 4 5 6 7 8 9 10 ...

跨度最深的覆盖范围是(6, 8),即3。

在这种情况下,预期收益应为(6,8)

  

我的解决方案

我不知道如何表示连续跨度,因此,我将每个连续跨度分解为数字列表,并尝试从计数器结果中找到最常见的一个。

from collections import Couter
import numpy as np

density = Counter()
for start, end in SPAN_LIST:
    density.update(
        np.round(np.arange(start, end, 0.01)), 2)
    )
most_dense_site, most_dense_count = density.most_common()[0]

结果可能不准确,并且对于大量列表(大约数十亿个项目)而言,速度非常慢。 我知道,如果提高精度,结果将更加准确,但同时也会浪费更多的内存。

我想知道如何加快流程并以更好的方式使结果更准确吗?

2 个答案:

答案 0 :(得分:1)

详细介绍评论部分:

解决方案是遍历范围的所有起点和终点,将它们混合在一起,以便“扫过”这些点。我们将考虑这些事件,并跟踪当前访问的范围。由范围开始触发的事件将增加当前访问范围的计数。范围结束触发的事件将减少当前访问范围的数量。

(下面的代码假定范围是半开的,包括开始但不结束。)

游乐场:https://ideone.com/fOAOXr

def deepest_coverage(span_list):
    if not span_list:
        raise ValueError("The given list must be non-empty")

    events = []
    for start, end in span_list:
        events.append((start, 1))
        events.append((end, -1))

    events.sort()

    ret = None
    most_visited = currently_visited = 0
    for i in range(len(events)):
        currently_visited += events[i][1]
        if currently_visited > most_visited:
            most_visited = currently_visited
            ret = events[i][0], events[i+1][0]

    return ret


print(deepest_coverage([(0, 4), (2, 8), (5, 10), (6, 9)]))

输出:

(6, 8)

资源:

答案 1 :(得分:0)

我用Python中的扫描线算法编写了此解决方案。

  1. 跨度列表并展平为“位置列表”,起点和终点的身份按分数记录。

  2. 合并相邻的起点和终点,以提高性能并修复错误的位置错误。

  3. 循环显示位置列表并记录其得分最深的范围。

from collections import defaultdict

def get_deepest_coverage(span_list):
    """Get the span with the deepest coverage."""
    pos_dict = defaultdict(int)
    for start, end in span_list:
        pos_dict[start] += 1
        pos_dict[end] -= 1
    pos_list = sorted((k, v) for k, v in pos_dict.items() if v)

    deepest_start = deepest_end = None
    deepest_count = current_count = 0
    for index, (pos, score) in enumerate(pos_list):
        current_count += score
        if current_count > deepest_count:
            deepest_count = current_count
            deepest_start, deepest_end = pos, pos_list[index + 1][0]

    return deepest_start, deepest_end, deepest_count


print(get_deepest_coverage([(2, 8), (5, 7), (7, 20)]))

感谢@miloszlakomy提供的所有材料。还有不错的解决方案。

(我花了整个下午写这篇摘要,发现@miloszlakomy在这里发布了答案。)


感谢xxx一直拒绝我的帖子全部,否则我将没有动力自己解决这个问题。