【问题标题】:Max interval intersection point最大区间交点
【发布时间】:2021-10-04 04:14:49
【问题描述】:

我正在尝试在 python 中实现逻辑。给定一组区间,找出交点数最多的区间。如果输入(1,6) (2,3) (4,11),则应返回(1,6)。这已在下面得到解答,但我无法在 python 中实现它。 given-a-set-of-intervals-find-the-interval-which-has-the-maximum-number-of-inte.

到目前为止,我正在使用以下逻辑。任何帮助将不胜感激。

def interval_intersection(intervals):
    if len(intervals) ==1:
        return intervals
    intervals.sort(key=lambda x: x[0])
    
    res =[intervals[0]]
    for i in range(1,len(intervals)):
        if intervals[i][0] > res[-1][1]:
            res.append(intervals[i])
        else:
            res[-1] = [min(res[-1][0],intervals[i][0]),max(res[-1][1],intervals[i][1])]
    return res

Examples:

  1. [[1,5],[5,10],[5,5]] 答案应该是[5,5] 在 tie [5,5] 的情况下,元素数量最少的区间。这里 [5,5] 在范围内只有 1 个元素,即 5,因此是 ans
  2. [[1,2],[3,5]] 没有交集返回-1

【问题讨论】:

  • 你能解释一下你的例子中maximum交互是什么意思吗?为什么不是 (3, 11) 或 (3, 4)?再举几个例子会有帮助。
  • 是的,请给一个示例测试用例。
  • 如果输入 (1,6) (2,3) (4,11),则应该返回 (1,6) -- 为什么?
  • 似乎他想要与其他区间有最多交集的初始区间,而不是最大源区间数覆盖的新区间
  • 好的,所以如果它们也被绑定,任何间隔都可以吗?例如,[1,2], [2,3]?如果没有,请尝试说明您使用的所有规则。另外,您的问题是关于如何将其他帖子中的伪代码实现为 Python,或者如何修改您的逻辑来解决问题?

标签: python algorithm intervals


【解决方案1】:

这是David Eisenstat's 算法的一个相当简单的实现。唯一的微妙之处是:

  1. 我假设所有间隔在两端都是封闭的,这意味着如果排序事件是同时发生的,则排序事件应该将开始放在结束之前。如果您想要完全打开或在右侧打开的区间,则需要颠倒此顺序。​​
  2. 返回的区间有最多的交叉点,首先按最小长度断开连接,然后按最早开始。
def interval_solve(intervals: Sequence[Sequence[int]]) -> Union[Sequence[int], int]:
    start_type = -1  # Assumes all intervals are closed
    end_type = 1

    events = [(s, start_type, i) for i, (s, e) in enumerate(intervals)]
    events.extend((e, end_type, i) for i, (s, e) in enumerate(intervals))
    events.sort()

    inter_count: Dict[int, int] = {}

    start_count = 0
    stop_count = 0

    for event_time, event_type, event_id in events:
        if event_type == start_type:
            start_count += 1
            inter_count[event_id] = -(stop_count + 1)
        else:
            stop_count += 1
            inter_count[event_id] += start_count

    # Find max by most intersections, then by shortest interval, then by earliest start
    answer = max(range(len(intervals)),
                 key=lambda j: (inter_count[j], intervals[j][0] - intervals[j][1]))
    if inter_count[answer] == 0:
        return -1
    return intervals[answer]

【讨论】:

    【解决方案2】:

    实际的想法很简单,我们对区间进行排序,并使用索引和布尔键存储其中的一些以指示开始或结束事件。

    然后,我们只是遍历它,同时计算索引之前的结束事件和开始事件。对于任何索引i,间隔重叠计数很简单,之前的开始事件数-之前的结束事件数(-1)。

    最后,我们可以在多个解决方案的情况下检查哪一个具有最小长度。

    # https://stackoverflow.com/questions/69426852/max-interval-intersection-point
    
    def max_interval_count(intervals):
        interval_sorted = []
        for idx, interval in enumerate(intervals):
            s, e = interval
            interval_sorted.append([s, idx, 0]) # 0 for start
            interval_sorted.append([e, idx, 1]) # 1 for end
        interval_sorted.sort(key = lambda x: x[0])
    
        print(interval_sorted)
    
        number_of_starts = 0
        number_of_ends = 0
    
        overlap_count = {} 
        for event in interval_sorted:
            _, idx, start_end = event
            if start_end == 0: # start event
                # subtract all the ending before it
                overlap_count[idx] = - (number_of_ends)
                number_of_starts += 1
            else: # end event
                overlap_count[idx] += (number_of_starts - 1) # -1 as we should not include the start from the same interval
                number_of_ends += 1
        print(overlap_count)
        ans_idx = -1
        max_over_count = 0
        min_len_interval = 99999999999
        for idx, overl_cnt in overlap_count.items():
            if overl_cnt > max_over_count:
                ans_idx = idx
                max_over_count = overl_cnt
            elif overl_cnt == max_over_count and overl_cnt > 0 and (intervals[idx][1] - intervals[idx][0] + 1) < min_len_interval:
                min_len_interval = (intervals[idx][1] - intervals[idx][0] + 1)
                ans_idx = idx
        if ans_idx == -1:
            return ans_idx
        return intervals[ans_idx]
    
    
    if __name__ == "__main__":
        test_1 = [[1,5],[5,10],[5,5]]
        test_2 = [[1,2],[3,5]]
        test_3 = [(1,6), (2,3), (4,11)]
        ans = max_interval_count(test_1)
        print(ans)
        print("---------")
        ans = max_interval_count(test_2)
        print(ans)
        print("---------")
        ans = max_interval_count(test_3)
        print(ans)
        print("---------")
    
    
    [[1, 0, 0], [5, 0, 1], [5, 1, 0], [5, 2, 0], [5, 2, 1], [10, 1, 1]]
    {0: 0, 1: 1, 2: 1}
    [5, 5]
    ---------
    [[1, 0, 0], [2, 0, 1], [3, 1, 0], [5, 1, 1]]
    {0: 0, 1: 0}
    -1
    ---------
    [[1, 0, 0], [2, 1, 0], [3, 1, 1], [4, 2, 0], [6, 0, 1], [11, 2, 1]]
    {0: 2, 1: 1, 2: 1}
    (1, 6)
    ---------
    

    【讨论】:

    • 你如何处理重叠的开始和结束?在第一个示例[[1,5],[5,10],[5,5]] 中,重叠计数似乎是{0: 0, 1: 1, 2: 1},这似乎不对——它们不应该都是 2 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多