数组(六)-- LC[1851] 包含每个查询的最小区间

2023-11-14

1 包含每个查询的最小区间

1.1 题目描述

给你一个二维整数数组 intervals ,其中 i n t e r v a l s [ i ] = [ l e f t i , r i g h t i ] intervals[i] = [left_i, right_i] intervals[i]=[lefti,righti] 表示第 i i i 个区间开始于 l e f t i left_i lefti 、结束于 r i g h t i right_i righti(包含两侧取值,闭区间)。区间的 长度 定义为区间中包含的整数数目,更正式地表达是 r i g h t i − l e f t i + 1 right_i - left_i + 1 rightilefti+1

再给你一个整数数组 queries 。第 j 个查询的答案是满足 l e f t i < = q u e r i e s [ j ] < = r i g h t i left_i <= queries[j] <= right_i lefti<=queries[j]<=righti 的 长度最小区间 i 的长度 。如果不存在这样的区间,那么答案是 -1 。

以数组形式返回对应查询的所有答案。

示例 1:
输入:intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5]
输出:[3,3,1,4]
解释:查询处理如下:

  • Query = 2 :区间 [2,4] 是包含 2 的最小区间,答案为 4 - 2 + 1 = 3 。
  • Query = 3 :区间 [2,4] 是包含 3 的最小区间,答案为 4 - 2 + 1 = 3 。
  • Query = 4 :区间 [4,4] 是包含 4 的最小区间,答案为 4 - 4 + 1 = 1 。
  • Query = 5 :区间 [3,6] 是包含 5 的最小区间,答案为 6 - 3 + 1 = 4 。

示例 2
输入:intervals = [[2,3],[2,5],[1,8],[20,25]], queries = [2,19,5,22]
输出:[2,-1,4,6]
解释:查询处理如下:

  • Query = 2 :区间 [2,3] 是包含 2 的最小区间,答案为 3 - 2 + 1 = 2 。
  • Query = 19:不存在包含 19 的区间,答案为 -1 。
  • Query = 5 :区间 [2,5] 是包含 5 的最小区间,答案为 5 - 2 + 1 = 4 。
  • Query = 22:区间 [20,25] 是包含 22 的最小区间,答案为 25 - 20 + 1 = 6 。

解法一:区间端点排序+离线查询+优先队列(小根堆)

首先我们对问题进行分析,对于第 j j j 个查询,可以遍历 intervals \textit{intervals} intervals,找到满足 left i ≤ queries j ≤ right i \textit{left}_i \le \textit{queries}_j \le \textit{right}_i leftiqueriesjrighti 的长度最小区间 i i i 的长度。以上思路对于每个查询,都需要重新遍历 intervals \textit{intervals} intervals

如果查询是递增的,那么我们可以对 intervals \textit{intervals} intervals 按左端点 left \textit{left} left 从小到大进行排序,使用一个指针 i i i 记录下一个要访问的区间 intervals [ i ] \textit{intervals}[i] intervals[i],初始时 i = 0 i = 0 i=0,使用优先队列 pq \textit{pq} pq 保存区间(优先队列的比较 key \textit{key} key 为区间的长度,队首元素为长度最小的区间)。对于第 j j j 个查询,我们执行以下步骤:

  1. 如果 i i i 等于 intervals \textit{intervals} intervals 的长度或 left i > queries [ j ] \textit{left}_i \gt \textit{queries}[j] lefti>queries[j],终止步骤;
  2. intervals [ i ] \textit{intervals}[i] intervals[i] 添加到优先队列 pq \textit{pq} pq,将 i i i 的值加 1,继续执行步骤 1。

此时所有符合 left ≤ queries j ≤ right \textit{left} \le \textit{queries}_j \le \textit{right} leftqueriesjright 的区间都在 pq \textit{pq} pq,我们不断地获取优先队列 pq \textit{pq} pq 的队首区间:

  • 如果队首区间的右端点 right < queries [ j ] \textit{right} \lt \textit{queries}[j] right<queries[j],那么说明该区间不满足条件,从 pq \textit{pq} pq 中出队;

如果队首区间的右端点 right ≥ queries [ j ] \textit{right} \ge \textit{queries}[j] rightqueries[j],那么该区间为第 j j j 个查询的最小区间,终止过程。

对于第 j + 1 j+1 j+1 个查询,因为查询是递增的,所以有 queries [ j + 1 ] ≥ queries [ j ] \textit{queries}[j + 1] \ge \textit{queries}[j] queries[j+1]queries[j],那么此时 pq \textit{pq} pq 中的区间都满足 left ≤ queries [ j + 1 ] \textit{left} \le \textit{queries}[j + 1] leftqueries[j+1]。在第 j j j 个查询中丢弃的区间有 right < queries [ j ] ≤ queries [ j + 1 ] \textit{right} \lt \textit{queries}[j] \le \textit{queries}[j + 1] right<queries[j]queries[j+1],因此丢弃的区间不满足第 j + 1 j + 1 j+1 个查询。同样在第 j + 1 j + 1 j+1 个查询执行与第 j j j 个查询类似的步骤,将可能满足条件的区间加入优先队列 pq \textit{pq} pq 中,那么此时所有满足条件的区间都在优先队列 pq \textit{pq} pq 中,执行类似第 j j j 个查询的出队操作。

由以上分析,如果查询满足递增的条件,那么可以利用优先队列进行优化。题目一次性提供所有的查询,基于离线原理,我们对所有查询从小到大进行排序,然后执行以上算法。

class Solution:
    def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
        n, m = len(intervals), len(queries)
        intervals.sort()
        queries = sorted((x, i) for i, x in enumerate(queries))
        ans = [-1] * m
        pq = []
        i = 0
        for x, j in queries:
            while i < n and intervals[i][0] <= x:
                a, b = intervals[i]
                heappush(pq, (b - a + 1, b))
                i += 1
            while pq and pq[0][1] < x:
                heappop(pq)
            if pq:
                ans[j] = pq[0][0]
        return ans

复杂度分析

  • 时间复杂度 O ( n × log ⁡ n + m × log ⁡ m ) O(n \times \log n + m \times \log m) O(n×logn+m×logm)
  • 空间复杂度 O ( n + m ) O(n + m) O(n+m)。其中 n 和 m 分别是数组 intervals 和 queries 的长度。

解法二:区间长度排序+离线询问+并查集

class Solution:
    def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
        m, n = len(intervals), len(queries)

        intervals.sort(key=lambda x: x[1] - x[0])
        queries = sorted([(q, i) for i, q in enumerate(queries)])

        fa = list(range(n + 1))

        def find(x):
            if x != fa[x]:
                fa[x] = find(fa[x])
            return fa[x]

        ans = [-1] * n

        for l, r in intervals:
            length = r - l + 1
            pos = bisect_left(queries, (l, -1))

            idx = find(pos)
            while idx < n and queries[idx][0] <= r:
                ans[queries[idx][1]] = length
                fa[idx] = idx + 1
                idx = find(idx + 1)

        return ans
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数组(六)-- LC[1851] 包含每个查询的最小区间 的相关文章

  • 《C和指针》笔记29:数组名和指针

    看下面的代码 int b 10 b 4 的类型是整型 但b的类型又是什么 它所表示的又是什么 一个合乎逻辑的答案是它表示整个数组 但事实并非如此 在C中 在几乎所有使用数组名的表达式中 数组名的值是一个指针常量 也就是数组第1个元素的地址
  • C语言实现快速排序与归并排序

    快排 代码如下 include
  • #LeetCode刷题——350. 两个数组的交集 II

    难度 easy 1 题目介绍 2 思路分析 第一种方法 双指针法 先对俩个数组进行排序 使用俩个指针 i 和 j 不停遍历nums1和nums2 比较俩个元素的值 如果相等就增加到结果集中 如果 nums1 i lt nums2 j 将 i
  • 数组扁平化(flatten)实现方案

    1 2 3 1 2 3 1 2 gt 1 2 3 1 2 3 1 2 上面的转换就是数组的扁平化 将一个嵌套多层的数组 array 转换为只有一层的数组 下面是实现数组扁平化的几种简单方法 1 递归 function flatten1 ar
  • C语言实验(十四):指针(数组排序,数组求平均数、中位数和众数)

    C语言实验 十四 指针 数组排序 数组求平均数 中位数和众数 一 输入10个整数 利用指针分别由小到大排序 由大到小排序 二 输入10个整数 通过指针引用数组 实现三个函数 分别求这10个整数的平均值 中位数 中值 数组名作为函数参数 通过
  • [leetcode] 358. Rearrange String k Distance Apart 解题报告

    题目链接 https leetcode com problems rearrange string k distance apart Given a non empty string str and an integer k rearran
  • 数组指针数组的定义及使用(about array of pointer of array)

    数组指针数组 array pointer array 该怎么定义和使用呢 如下 定义 define MsgCnt 3 define MsgLen 8 typedef char MsgArray MsgCnt MsgLen typedef c
  • 百度:度度熊有一个N个数的数组,他想将数组从大到小排好序...

    度度熊有一个N个数的数组 他想将数组从大到小排好序 但是萌萌的度度熊只会下面这个操作 任取数组中的一个数然后将它放置在数组的最后一个位置 问最少操作多少次可以使得数组从小到大有序 输入描述 首先输入一个正整数N 接下来的一行输入N个整数 N
  • Java常见排序:(三)快速排序

    快速排序是一种非常快的交换排序方法 思路很简单 将待排的数据序列中任意取一个数据作为分界值 所有比这个值小的放在左边 比他大的放在右边 形成左右两个子序列 左边的值都比分界值小 右边的值都比分界大 接下来对左右两个子序列进行递归 两个子序列
  • 四种排序:选择,插入,冒泡,快速排序原理及其对应的时间、空间复杂度解析

    四种排序 选择 插入 冒泡 快速排序原理及其对应的时间空间复杂度 首先 在了解四种排序之前 让我们来了解一下什么是时间复杂度和空间复杂度 时间复杂度 算法的时间复杂度是一个函数 它定性描述该算法的运行时间 记做T n 直白的来说 就是指运行
  • 数组--二维数组

    JAVA的二维数组 二维数组 在二维数组中的每一个元素中都是一个一维数组 意思就是两个一维数组相嵌套而成的数组 二维数组的声明 有一下两种 int a int a 在声明时 一般推荐第一种情况 方便代码阅读 二维数组在创建时也要给定数组的长
  • python 数组操作中的 “:” “:: ” “, ” python 中的 [:-1] 和 [::-1] [-1:-2:-1] [

    使用python版本3 7 首先先了解下python3 7中的下标 python下标有两套 一套是正的 一套是负的 引入负坐标的意义应该是方便将数组中的数据从右往左访问 a python 中的python 的下标描述如下 组 p y t h
  • Java 中Arrays工具类的使用

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 介绍 java util Arrays类即为操作数组的工具类 包含了用来操作数组 比如排序和搜索 的各种算法 下面我用代码给大家演示一下
  • 【100%通过率 】【华为OD机试c++\python】组合出合法最小数【2023 Q1 A卷

    华为OD机试 题目列表 2023Q1 点这里 2023华为OD机试 刷题指南 点这里 题目描述 给一个数组 数组里面都是代表非负整数的字符串 将数组里所有的数值排列组合拼接起来组成一个数字 输出拼接成的最小的数字 输入描述 一个数组 数组不
  • mysql按照某个字段值内容排序

    举个栗子 假如一个商品下 有多个货品 各个货品的状态值都不一样 那么当只想展示商品中的某一个货品时 希望用户端看到的优先级是在售的货品中的一个 根据mysql提供的方法 field column value1 value2 value3 可
  • 数学(五) -- LC[415]&[455] 字符串相加与两数相加

    1 字符串相加 1 1 题目描述 给定两个字符串形式的非负整数 num1 和num2 计算它们的和并同样以字符串形式返回 你不能使用任何內建的用于处理大整数的库 比如 BigInteger 也不能直接将输入的字符串转换为整数形式 示例 1
  • 数组的一些简单操作,列表改数组,数组合并,数组存取

    数组的简单操作 总用的一些操作 记录一下 要不总忘 1列表改数组 import numpy as np a 1 2 3 4 a np array a 输出a array 1 2 3 4 2数组合并 延竖轴拼接数组 aa np vstack
  • 输出数组的最大值、最小值及其位置

    题目 输入一个长度为10的数组 输出数组的最大值 最小值及其最大值 最小值在数组里的位置 思路 如果只需找出最大值 我们可以假定最大值max为数组的第一个元素 然后将剩余的元素逐个和max比较 如果有比max更大的元素 就将其记录下来 直到
  • 八大排序算法(六)——优先队列、堆和堆排序

    6 1 API 优先队列是一种抽象数据类型 它表示了一组值和对这些值的操作 优先队列最重要的操作就是删除最大元素和插入元素 6 2 初级实现 6 2 1 数组实现 无序 或许实现优先队列最简单方法就是基于下压栈的代码 insert 方法的代
  • C++基础-一维和二维数组详解

    目录 定义 一维数组 二维数组 定义 数组是相同类型的对象序列 它们占据一块连续的内存区 一维数组

随机推荐