【问题标题】:Python list manipulation: Given a list of ranges number, return the list of combined rangesPython 列表操作:给定范围编号列表,返回组合范围列表
【发布时间】:2017-02-17 07:51:35
【问题描述】:

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

假设有一个范围列表。例如,[[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. 遍历列表并找到范围

我知道这个解决方案绝对是他们正在寻找的(这就是我面试失败的原因),因为时间复杂度是 O(nlogn)(排序),n 是范围内不同数字的数量。

python 专家能否给出一个 O(n) 的解决方案,n 为原始列表中的范围数?

【问题讨论】:

  • 可以有空范围吗?
  • 您的意思是说这绝对是不是他们正在寻找的东西吗?
  • 范围内数字的最大值是多少,例如如果范围是 [x,y],x 和 y 的最大值是多少?如果它更少,你可以在 O(max_val(x))

标签: python algorithm list sorting


【解决方案1】:

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

  1. 按段的起点对段进行排序。
  2. 扫过排序列表并检查当前段是否与前一个段重叠。如果是,则根据需要扩展上一段。

示例代码:

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】:

    您可以使用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 是范围数。

    【讨论】:

      【解决方案3】:

      如果范围是 [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)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-04
        • 2015-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多