概览
根据一个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原题
给定一个会议时间安排的数组 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