leetcode_632_最小区间

最小区间

描述

困难

你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。

我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

示例 1:

输入:[[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] 中。

注意:

  • 给定的列表可能包含重复元素,所以在这里升序表示 >= 。
  • 1 <= k <= 3500
  • -105 <= 元素的值 <= 105

解题

目标是找一个最小区间,使得k个列表中的每个列表至少有一个数包含在其中

设置一个列表k_elements,里面包含k个数,分别是k个列表中的包含在这个区间的数

那么这个最小区间的左端点为这k个数中的最小值,右端点为这k个数中的最大值

那么只需要更新该列表就行了

例如,k_elements中的数为a_11、a_21、…、a_k1

  • 下标第一个数表示属于k个列表中的哪个列表
  • 下标第二个数表示在对应列表中的下标

若其中最小的数为a_i1,最大的数为a_j1,那么区间为[a_i1,a_j1]

此时最小的数为a_i1,则从原数组中取出a_i2代替a_i1,然后再更新区间左右端点

算法步骤

  • 设置一个列表k_elements,其中中的元素为k个列表中的第一个值,共k个值
  • 设置一个列表indices用于保存k_elements中的数据是分别是k个列表中的下标
  • 设置初始left和right指针表示列表中的最小值最大值(设置需要返回的结果start和end为初始left和right)
  • 每次选择k_elements中的最小的数(left)
    • 如果该数已经是对应列表中的最后一个数,退出循环
    • 将这个数所属列表中,这个数的后面一个数更新至这个数的位置上
    • 如果更新后的数大于原k_elements中的最大的数(right),更新right
    • 重新获得k_elements中的最小的数作为left
    • 如果现在[left, right]区间小于[start, end],更新start和end

最后的效率可能不高,击败了8%左右的用户

from typing import List


class Solution:
    def smallestRange(self, nums: List[List[int]]) -> List[int]:
        k = len(nums)
        # 用于保存该区间中的k个列表中的某个元素
        k_elements = [nums[i][0] for i in range(k)]
        # 用于保存这k个数在各自列表中的下标
        indices = [0 for _ in range(k)]
        # 初始区间为k个元素的最小值到最大值
        start = left = min(k_elements)
        end = right = max(k_elements)
        length = end - start 

        while True:
            # 获取最小值所在的数组的下标
            index = k_elements.index(left)
            # 如果该最小值为所在数组的最后一个值,退出
            if indices[index] == len(nums[index]) - 1:
                break
            # 该最小值所在数组的位置后移一个位置
            # 将后一个数据更新到k_elements中
            indices[index] += 1
            k_elements[index] = nums[index][indices[index]]
            # 如果更新后的数大于右端,则更新右段指针
            if k_elements[index] > right:
                right = k_elements[index]
			# 更新最小值
            left = min(k_elements)
			# 更新区间
            if right - left < length:
                start = left
                end = right
                length = right - left

        return [start, end]


if __name__ == '__main__':
    nums = [[4, 10, 15, 24, 26], [0, 9, 12, 20], [5, 18, 22, 30]]
    print(Solution().smallestRange(nums))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值