📜  使范围不重叠所需的最小移除量(1)

📅  最后修改于: 2023-12-03 15:36:42.444000             🧑  作者: Mango

使范围不重叠所需的最小移除量

当我们需要处理一些范围或者区间时,我们可能需要考虑如何使这些范围不重叠。比如在调度任务时,需要避免任务之间的时间重叠,这个时候就需要考虑如何使任务的时间范围不重叠。

以下是一些处理范围不重叠的方法和算法。

贪心算法

对于一组范围,我们可以按照范围的结束时间来排序,然后从第一个范围开始,依次看后面的范围是否与当前范围重叠。如果重叠了,就把后面的范围移除掉。如果不重叠,则把当前范围变成新的不重叠范围的结束范围,依次遍历后面的范围。

这个算法的时间复杂度是O(nlogn),其中n是范围的个数。这个算法很容易理解,也很好实现。

以下是排序的python代码:

ranges.sort(key=lambda x:x[1])  # 按照结束时间排序

以下是范围不重叠算法的python代码:

def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
    if not intervals:
        return 0

    ranges = sorted(intervals, key=lambda x: x[1])
    count = 1
    end = ranges[0][1]

    for i in range(1, len(ranges)):
        if ranges[i][0] >= end:
            end = ranges[i][1]
            count += 1

    return len(intervals) - count
动态规划

另一种方法是使用动态规划来解决问题。我们可以定义一个一维数组dp,其中dp[i]表示前i个范围中,最多能有多少个不重叠的范围。我们可以按照开始时间来排序范围,然后依次考虑每个范围是否可以加入到前面的范围中。

如果当前范围的开始时间大于前一个范围的结束时间,并且当前范围的结束时间小于等于前一个范围之前所有不重叠范围的结束时间中的最小值,那么可以把当前范围加入到前面的范围中,此时dp[i] = dp[i-1]+1。否则,不能加入到前面的范围中,此时dp[i] = dp[i-1]。

这个算法的时间复杂度是O(n^2),其中n是范围的个数。这个算法比较复杂,需要考虑很多细节。

def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
    if not intervals:
        return 0

    intervals.sort(key=lambda x:x[0])
    n = len(intervals)
    dp = [1] * n

    for i in range(1, n):
        for j in range(i):
            if intervals[i][0] >= intervals[j][1]:
                k = j - 1
                while k >= 0 and intervals[i][0] < intervals[k][1]:
                    k -= 1
                
                if k < 0:
                    dp[i] = max(dp[i], dp[j] + 1)
                else:
                    dp[i] = max(dp[i], dp[j] + dp[k+1])
            else:
                dp[i] = max(dp[i], dp[j])
    
    return n - dp[-1]

以上就是两种处理范围不重叠的算法,其中贪心算法是比较常用的算法,而动态规划算法更加复杂,但也更加灵活。