【问题标题】:Merge two list ,element is a range value合并两个列表,元素是一个范围值
【发布时间】:2021-08-27 06:41:09
【问题描述】:

说明:

  • 我需要有效地合并两个列表,它们的元素是 serval(至少 10000)次的范围值。如果可以,所有元素都应该合并。
  • 两个列表已经排序。
  • 每个元素都是严格分开的,这意味着这些情况是非法的:
list1 = [[1, 3], [3, 6]]
list2 = [[1, 4], [2, 5]]

list1 = [[1, 5], [6, 10]]
list2 = [[2, 4], [5, 8]]

示例:

#elements: 0:start(inclusive) 1:stop(inclusive).
#the `ans` become next `list1`, to merge a new `list2` .

#input1:
list1 = [[1, 1],[3, 3]]
list2 = [[5, 5]]
#output1:
ans = [[1, 1], [3, 3], [5, 5]]

#input2:
list1 = [[1, 1], [3, 3], [5, 5]]
list2 = [[2, 2]]
#output2:
ans = [[1, 3], [5, 5]] # [1,1]+[2,2]+[3,3] = [1,3]

#input3:
list1 = [[1, 3], [5, 5]]
list2 = [[0, 0], [4, 4], [6, 6]]
#output:
ans = [[0,6]] #[0,0]+[1,3]+[4,4]+[5,5]+[6,6] = [0,6]

我尝试过的:

    def merge(list1,list2):
        ans = sorted(list1+list2,key = lambda x:x[0])
        idx = 0
        while idx<len(ans):
            try:
                if ans[idx][1] == ans[idx+1][0] - 1:
                    ans[idx] = [ans[idx][0],ans[idx+1][1]]
                    del ans[idx+1]
                elif ans[idx][0] == ans[idx+1][1] + 1:
                    ans[idx] = [ans[idx+1][0],ans[idx][1]]
                    del ans[idx+1]
                else:
                    idx+=1
            except Exception:
                idx+=1
        return ans
  • 它可以工作,但速度很慢。解决一个难题大约需要 15 秒,解决一个简单案例大约需要 1.2 秒。
  • 解决难题所需的时间少于 3 秒。

问题

  • 有更好的解决方案吗?
  • 或者我应该使用哪种算法?也许是分段树?

【问题讨论】:

  • 这两个列表本身是否已经排序?您的所有示例输入都表明它们是。
  • @schwobaseggl 是的,两个列表已经排序。

标签: python algorithm


【解决方案1】:

您没有使用所有信息。列表已经排序,因此不需要将它们连接起来并重新排序。

def merge(list1, list2):
    # helper to process one interval from a given list
    def consume(lst, index):
        start, end = interval = lst[index]
        if not result or result[-1][-1] < start - 1:
            result.append(interval)
        elif result[-1][-1] < end:
            result[-1][-1] = end
        return index + 1

    result = []
    i1 = i2 = 0
    while i1 < len(list1) and i2 < len(list2):
        # saving some boilerplate code to always work on list1
        if list1[i1] > list2[i2]:
            list1, i1, list2, i2 = list2, i2, list1, i1
        i1 = consume(list1, i1)
    while i2 < len(list2):
        i2 = consume(list2, i2)
    return result

list1 = [[1, 1],[3, 3]]
list2 = [[5, 5]]
merge(list1, list2)
# [[1, 1], [3, 3], [5, 5]]
list1 = [[1, 1], [3, 3], [5, 5]]
list2 = [[2, 2]]
merge(list1, list2)
# [[1, 3], [5, 5]]
list1 = [[1, 3], [5, 5]]
list2 = [[0, 0], [4, 4], [6, 6]]
merge(list1, list2)
# [[0, 6]]

这种方法的算法优势似乎被 Python 对上下文变化(尤其是嵌套函数)排序的蛮力 C-Power 所抵消。可以尝试稍微改进@trincot 建议的解决方案(不是设计方面,而是从纯粹的时间/空间效率的角度来看):

def merge(list1, list2):
    # sorted(l1+l2)  creates 2 new lists in memory
    list1.extend(list2)
    list1.sort()
    result = list1[:1]
    for interval in list1:
        start, end = interval
        _, e = last = result[-1]
        if e < start - 1:
            result.append(interval)
        elif e < end:  
            last[-1] = end
    return result

【讨论】:

  • 对不起,我尝试了您的解决方案,但解决一个困难的案例仍然需要 15 秒,而 @trincot 解决方案对于相同的案例需要 5 秒。为您的努力 +1。
  • stackoverflow.com/questions/464342/…,它显示元素是否小于 1000000,连接并使用它可能是更有效的解决方案。
  • 这也是我的解决方案,因为时间复杂度只是线性的O(n+m)。也许 Python 中的 sorted 功能是如此之快,以至于它击败了这里制作的所有必要的额外循环:)
  • 是的,sorted 是用编译后的代码实现的,所以对于有限的列表大小(可能低于一百万),它仍然比在 Python 中“手动”循环更快,即使有时间复杂性差异。
  • 还要小心:这个解决方案会变异输入列表中的一些元素。我会对其进行一些更改,以便结果由新对组成。调用者在拨打merge 后发现他们的输入列表被更改可能会令人惊讶。
【解决方案2】:

del 会对性能产生影响...尽量避免。我认为最好让答案列表从一个空列表开始,然后在后面附加范围。

另外,我认为向sorted 提供key 参数是不值得的:默认情况下,无论如何它都会按对中的第一个值进行排序,如果有平局,它将按第二个值。

这是它的工作原理:

def merge(list1,list2):
    ans = []
    last = [None, -float("inf")]
    for start, end in sorted(list1+list2):
        if start > last[1] + 1:
            last = [start, end]
            ans.append(last)
        elif end > last[1]:  # Merge:
            last[1] = end  # We mutate a pair that is already in the result
    return ans

【讨论】:

  • 谢谢!它比我的要快得多,解决一个难题大约需要 5.2 秒。我想看看更多的解决方案,所以如果我明天没有更好的解决方案,我会接受你的回答。
猜你喜欢
  • 2019-03-21
  • 2019-04-28
  • 2021-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-27
  • 2015-05-26
  • 2022-11-03
相关资源
最近更新 更多