区间的交并补操作:自我实现和interval源码

概览

根据一个leetcode题目散发,想要自己实现一下区间的交并补操作,然后再看一下相关库(interval)的源码,比较学习一下

自我实现

不论开闭/列表表示 版本

默认所有区间都是两边都是闭区间

交集

def intersection(lis_one: list, lis_two: list):
    # if not isinstance(lis_one, list) or not isinstance(lis_two, list):
    #     print("param_one and param_two should be list")
    #     return
    # elif len(lis_one) != 2 or len(lis_two) != 2:
    #     print("the length of param_one and param_two should be 2")
    #     return

    left = max(lis_one[0], lis_two[0])
    right = min(lis_one[1], lis_two[1])
    if left <= right:
        return [left, right]
    else:
        return "empty"


print(intersection([1, 3], [2, 4])) # [2,3]
print(intersection([1, 4], [2, 3])) # [2,3]
print(intersection([1, 2], [3, 4])) # empty

选取两个区间左值的最大值,右值的最小值,在有交集的情况下,就直接能得到交集;而在没有交集的情况下,左值的最大值属于较大区间,而右值的最小值属于较小区间,那么会出现left > right 的情况,以此作为判定标准

在这里插入图片描述

并集

def union(list_one, list_two):
    left = min(list_one[0], list_two[0])
    right = max(list_one[1], list_two[1])

    other_left = max(list_one[0], list_two[0])
    other_right = min(list_one[1], list_two[1])

    if other_left > other_right:
        return [left, other_right], [other_left, right]
    else:
        return [left, right]


print(union([1, 2], [3, 4])) # ([1, 2], [3, 4])
print(union([1, 4], [2, 3])) # [1, 4]
print(union([1, 3], [2, 4])) # [1, 4]

补集

def ComplementarySet(larger_list, smaller_list):
    # 验证第二参数是否为第一参数的子集
    if intersection(larger_list, smaller_list) != smaller_list:
        return '%s is not a subset of %s' % (repr(larger_list), repr(smaller_list))
    fisrt_left = larger_list[0]
    fisrt_right = smaller_list[0]
    second_left = smaller_list[1]
    second_right = larger_list[1]
    first = [fisrt_left, fisrt_right]
    second = [second_left, second_right]

    if fisrt_left == fisrt_right:
        first = None

    if second_left == second_right:
        second = None

    if first and second:
        return first, second
    elif first:
        return first
    elif second:
        return second
    else:
        return 'empty'

interval库的实现

interval的交集用__and__()来重载&运算符实现

首先判断,两个待交集对象是否相同,如果相同那么直接返回一个

def __and__(self, other):
    if self == other:
        result = Interval()
        result.lower_bound = self.lower_bound
        result.upper_bound = self.upper_bound
        result.lower_closed = self.lower_closed
        result.upper_closed = self.upper_closed

然后用内置的comes_before()函数来判断相对位置,再通过内置的overlaps()函数来判断是否重叠,明确了相对位置和是否重叠之后就可以直接获得交集的左右边界,源码如下

        # 通过comes_before()来使得self永远是左边的区间
    	elif self.comes_before(other):
            # 通常情况下考虑有重叠的情况
            if self.overlaps(other):
                # 确定交集左边界
                if self.lower_bound == other.lower_bound:
                    lower = self.lower_bound
                    lower_closed = min(self.lower_closed, other.lower_closed)
                elif self.lower_bound > other.lower_bound:
                    lower = self.lower_bound
                    lower_closed = self.lower_closed
                else:
                    lower = other.lower_bound
                    lower_closed = other.lower_closed
                # 确定交集右边界    
                if self.upper_bound == other.upper_bound:
                    upper = self.upper_bound
                    upper_closed = min(self.upper_closed, other.upper_closed)
                elif self.upper_bound < other.upper_bound:
                    upper = self.upper_bound
                    upper_closed = self.upper_closed
                else:
                    upper = other.upper_bound
                    upper_closed = other.upper_closed
                    
                result = Interval(
                    lower, upper, 
                    lower_closed=lower_closed, upper_closed=upper_closed)
            # 没有重叠的情况直接返回空集
            else:
                result = Interval.none()
        else:
            result = other & self
        return result

类似的思路如果用上面自己实现的形式如下:

def innersection(list_one, list_two):
    # 确定相对位置靠左的
    left_list = []
    right_list = []
    left = 0
    if list_one[0] < list_two[0]:
        left_list = list_one
        right_list = list_two
    elif list_one[0] > list_two[0]:
        left_list = list_two
        right_list = list_one
    else:
        return [list_one[0], min(list_one[1], list_two[1])]
    # 判断重叠
    if left_list[1] < right_list[0]:
        return "empty"
    # 重叠的情况下
    else:
        left = right_list[0]
        right = min(left_list[1], right_list[1])

    return [left, right]


print(innersection([1, 4], [2, 3])) # [2, 3] 
print(innersection([1, 2], [3, 4])) # empty
print(innersection([1, 3], [2, 4])) # [2, 3]

参考资料

Leetcode原题

252. 会议室 - 力扣(LeetCode)

给定一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,请你判断一个人是否能够参加这里面的全部会议。

示例 1:

输入:intervals = [[0,30],[5,10],[15,20]]
输出:false
示例 2:

输入:intervals = [[7,10],[2,4]]
输出:true

提示:

0 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti < endi <= 106

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值