合并Python中的重叠间隔

时间:2018-03-02 14:24:27

标签: python algorithm data-structures merge overlap

我正在尝试解决需要合并重叠间隔的问题:https://leetcode.com/problems/merge-intervals/description/

问题是:

  

给定一系列间隔,合并所有重叠的间隔。

     

例如,给定[1,3],[2,6],[8,10],[15,18],返回[1,6],[8,10],[15,18]。

我尝试了我的解决方案:

# Definition for an interval.
# class Interval:
#     def __init__(self, s=0, e=0):
#         self.start = s
#         self.end = e

class Solution:
    def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        start = sorted([x.start for x in intervals])
        end = sorted([x.end for x in intervals])

        merged = []
        j = 0
        new_start = 0

        for i in range(len(start)):
            if start[i]<end[j]:
                continue
            else:
                j = j + 1
                merged.append([start[new_start], end[j]])
                new_start = i


        return merged

然而,显然缺少最后一个间隔:

Input : [[1,3],[2,6],[8,10],[15,18]]

Answer :[[1,6],[8,10]]

Expected answer: [[1,6],[8,10],[15,18]]

不确定如何包含最后一个间隔,因为只能在正向模式下检查重叠。

如何修复我的算法以使其工作到最后一个插槽?

感谢您的帮助。

4 个答案:

答案 0 :(得分:1)

您的代码隐式已经假设要对排序的开始和结束进行排序,因此可以省略排序。要查看此信息,请尝试以下时间间隔:

intervals = [[3,9],[2,6],[8,10],[15,18]]
start = sorted([x[0] for x in intervals])
end = sorted([x[1] for x in intervals]) #mimicking your start/end lists
merged = []
j = 0
new_start = 0

for i in range(len(start)):
    if start[i]<end[j]:
        continue
    else:
        j = j + 1
        merged.append([start[new_start], end[j]])
        new_start = i
print(merged) #[[2, 9], [8, 10]]

无论如何,执行此操作的最佳方法可能是递归,此处显示的是列表而不是Interval个对象。

def recursive_merge(inter, start_index = 0):
    for i in range(start_index, len(inter) - 1):
        if inter[i][1] > inter[i+1][0]:
            new_start = inter[i][0]
            new_end = inter[i+1][1]
            inter[i] = [new_start, new_end]
            del inter[i+1]
            return recursive_merge(inter.copy(), start_index=i)
    return inter    

sorted_on_start = sorted(intervals)
merged = recursive_merge(sorted_on_start.copy())
print(merged) #[[2, 10], [15, 18]]

答案 1 :(得分:1)

这已经很老了,但万一有人偶然发现这个,我想我会投入我的两分钱,因为我对上面的答案并不完全满意。

我将在我的解决方案开头说,当我使用间隔时,我更喜欢将它们转换为 python3 ranges(可能是您的 Interval 类的优雅替代品),因为我发现它们易于使用。但是,您需要记住,范围与 Python 中的其他所有内容一样是半开的,因此停止坐标不在间隔的“内部”。对我的解决方案无关紧要,但要记住一些事情。

我自己的解决方案:

# Start by converting the intervals to ranges.
my_intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
my_ranges = [range(start, stop) for start, stop in my_intervals]


# Next, define a check which will return True if two ranges overlap.
# The double inequality approach means that your intervals don't
# need to be sorted to compare them.
def overlap(range1, range2):
    if range1.start <= range2.stop and range2.start <= range1.stop:
        return True
    return False


# Finally, the actual function that returns a list of merged ranges.
def merge_range_list(ranges):
    ranges_copy = sorted(ranges.copy(), key=lambda x: x.stop)
    ranges_copy = sorted(ranges_copy, key=lambda x: x.start)
    merged_ranges = []

    while ranges_copy:
        range1 = ranges_copy[0]
        del ranges_copy[0]

        merges = []  # This will store the position of ranges that get merged.

        for i, range2 in enumerate(ranges_copy):
            if overlap(range1, range2):  # Use our premade check function.
                range1 = range(min([range1.start, range2.start]),  # Overwrite with merged range.
                               max([range1.stop, range2.stop]))
                merges.append(i)

        merged_ranges.append(range1)

        # Time to delete the ranges that got merged so we don't use them again.
        # This needs to be done in reverse order so that the index doesn't move.
        for i in reversed(merges):
            del ranges_copy[i]

    return merged_ranges

print(merge_range_list(my_ranges))  # --> [range(1, 6), range(8, 10), range(15, 18)]

答案 2 :(得分:0)

为每个端点建立配对:(value; kind = +/-1 for start or end of interval)

按值排序。如果您需要合并具有重合结束的区间(如0-1和1-2

),则在第一次选择paie时使用-1

制作CurrCount = 0,浏览排序列表,将kind添加到CurrCount 当CurrCount变为非零时开始新的结果间隔,当CurrCount变为零时结束间隔。

答案 3 :(得分:0)

我们可以按第一个间隔排序间隔,我们可以通过逐个检查间隔而不是附加到另一个间隔来在同一间隔列表中构建合并列表。我们为每个间隔增加iinterval_index是当前间隔检查

x =[[1,3],[2,6],[8,10],[15,18]]
#y  = [[1,3],[2,6],[8,10],[15,18],[19,25],[20,26],[25,30], [32,40]]

def merge_intervals(intervals):
    sorted_intervals = sorted(intervals, key=lambda x: x[0])
    interval_index = 0
    #print(sorted_intervals)
    for  i in sorted_intervals:

        if i[0] > sorted_intervals[interval_index][1]:
            interval_index += 1
            sorted_intervals[interval_index] = i
        else:
            sorted_intervals[interval_index] = [sorted_intervals[interval_index][0], i[1]]
    #print(sorted_intervals)
    return sorted_intervals[:interval_index+1]

print(merge_intervals(x)) #-->[[1, 6], [8, 10], [15, 18]]
#print ("------------------------------")
#print(merge_intervals(y)) #-->[[1, 6], [8, 10], [15, 18], [19, 30], [32, 40]]