【每日算法】最小区间
题目描述
这是 LeetCode 上的 632.最小区间,
难度为 【困难】
你有 k 个 非递减排列 的整数列表。找到一个 最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
示例 1:
输入:nums = [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
输出:[20,24]
解释:
列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。
列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。
列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。
示例 2:
输入:nums = [[1,2,3],[1,2,3],[1,2,3]]
输出:[1,1]
示例 3:
输入:nums = [[10,10],[11,11]]
输出:[10,11]
示例 4:
输入:nums = [[10],[11]]
输出:[10,11]
示例 5:
输入:nums = [[1],[2],[3],[4],[5],[6],[7]]
输出:[1,7]
提示:
nums.length == k
1 <= k <= 3500
1 <= nums[i].length <= 50
-10^5 <= nums[i][j] <= 10^5
nums[i] 按非递减顺序排列
分析题目要求
找到一个区间,要求区间内包括k个列表中每个列表最少一个数字。
首先合并k个列表,保存当前数组所在的数组,并按升序进行排列
[(0,1),(4,0),(5,2),(9,1),(10,0),(12,1),(15,0),(18,2),(20,1),(22,2),(24,0),(26,0),(30,2)]
这样就变成了与76.最小覆盖子串一样的题目了
定义一个窗口,窗口内包括k个列表的索引(0,1,2...k),并且最小值和最大值的差值最小,一直遍历到最后结尾,就找到了满足要求的答案了
代码实现
import collections
class Solution(object):
def smallestRange(self, nums):
all_nums=[]
k=len(nums)
need=collections.defaultdict(int)
for i in range(k):
need[i]+=1
for j in range(len(nums[i])):
all_nums.append((nums[i][j],i))
all_nums=sorted(all_nums,key=lambda x:x[0])
res=[0,float('inf')]
i=0
# print(need)
for num,f in all_nums:
# print(num,f)
if need[f]>0:
k-=1
need[f]-=1
if k==0:
while need[all_nums[i][1]]<0:
need[all_nums[i][1]]+=1
i+=1
# print(need)
if res[1]-res[0]>num-all_nums[i][0]:
res=(all_nums[i][0],num)
k+=1
need[all_nums[i][1]]+=1
i+=1
return [] if res[1]>all_nums[len(all_nums)-1][0] else [res[0],res[1]]