Python列表操作:给定范围编号列表,返回组合范围列表

时间:2017-02-17 07:51:36

标签: python algorithm list sorting

在电话采访中我遇到了这个问题:

  

假设有一个范围列表。例如,[[1-6],[10-19],[5-8]]。   编写一个返回组合范围列表的函数   这样函数返回[[1-6],[10-19],[5-8]]   [[1,8],[10,19]](仅限开始和结束编号)。注意,输入列表   可以包含任意数量的   的范围内。

我对此问题的解决方案是:

  1. 将所有范围列表合并到一个列表中: [[1-6],[10-19],[5-8]] - > [1-6,10-19,5-8]

  2. 在列表上执行排序: list = Sorted(list) - > [1,2,3,4,5,5,6,6,7,8,10 ...]

  3. 使用list = set(list)删除多余的数字

  4. 遍历列表并找到范围

  5. 我知道这个解决方案肯定是他们正在寻找的(这就是为什么我的采访非常失败)因为时间复杂度是O(nlogn)(排序),n是范围内不同数字的数量。

    你能告诉python expert一个O(n)解决方案,n是原始列表中的范围数吗?

3 个答案:

答案 0 :(得分:2)

您可以使用heapq从范围创建堆。然后从堆中弹出范围,如果它与堆顶部重叠,则用合并范围替换顶部。如果没有重叠,或者没有更多的范围将其附加到结果:

import heapq

def merge(ranges):
    heapq.heapify(ranges)
    res = []

    while ranges:
        start, end = heapq.heappop(ranges)
        if ranges and ranges[0][0] <= end:
            heapq.heapreplace(ranges, [start, max(end, ranges[0][1])])
        else:
            res.append((start, end))

    return res

ranges = [[1,6],[10,19],[5,8]]
print(merge(ranges))

输出:

[(1, 8), (10, 19)]

以上 O(n log n)时间复杂度, n 是范围数。

答案 1 :(得分:2)

首先,问题中提到的解决方案不是O(nlgn),其中n是段的数量。这是O(Xlg(X)),其中X = length of the segment*num of segments非常慢。 存在O(NlgN)解,其中N是段的数量。

  1. 按照起点对细分进行排序。
  2. 扫过已排序的列表,检查当前段是否与前一段重叠。如果是,则在需要时扩展前一段。
  3. 示例代码:

    inp = [[1,6], [10,19], [5,8]]
    
    inp = sorted(inp)
    segments = []
    
    for i in inp:
        if segments:
            if segments[-1][1] >= i[0]:
                segments[-1][1] = max(segments[-1][1], i[1])
                continue
        segments.append(i)
    
    print segments # [[1, 8], [10, 19]]
    

答案 2 :(得分:1)

如果范围是[x,y]和max_x,y可能在几百万之内,你可以做到这一点

我的想法是,我使用散列技术将它们排序,利用较低的max_y。

然后我们迭代并保持现有的“好”。范围是变量mn和mx。

当一个新范围出现时,如果它完全超出了“好”的范围。范围,我们追加良好的范围,并使新的范围作为良好的范围。否则我们会相应改变好的范围。

max_y = 1000000
range_sort = [None]*max_y

ranges =  [[1,6],[10,19],[5,8]]
for r in ranges:
    if range_sort[r[0]] is not None and range_sort[r[0]]>=r[1]:
         continue   ## handling the case [1,5] [1,8]
    range_sort[r[0]] = r[1]   # in the list lower value is stored as index, higher as value

mx = -1
mn = 1000000000
ans = []
for x,y in enumerate(range_sort): # The values are correct as explained in comment above
    if y is None:
        continue   #To remove the null values

    if x<mn:
        mn = x    # This will change the lower value of current range

    if x>mx and mx>0: # If lower val x higher than current upper mx
        ans.append([mn,mx])  # append current lower (mn) and upper(mx)
        mn = x   
        mx = y   # change the current upper and lower to the new one 

    if y>mx:
        mx = y   # This will change upper value of current range

ans.append([mn,mx]) # This has to be outside as last range won't get appended

print ans

输出:[[1,8],[10,19]]

时间复杂度 O(MAX_y)