LeetCode·每日一题·1851. 包含每个查询的最小区间·优先队列(小顶堆)

题目

 

示例

 

思路

  • 离线查询:
    •  输入的结果数组queries[]是无序的。如果我们按照输入的queries[]本身的顺序逐个查看,时间复杂度会比较高。 于是,我们将queries[]数组按照数值大小,由小到大逐个查询,这种方法称之为离线查询。
  • 位运算:
    •  离线查询的时候,queries[]可以按照数值大小逐个查看,但最终返回的结果数组,是需要按照queries[]相同的顺序输出的,也就是说,queries[]数组的下标信息不能被丢失。 此时,我们可以考虑,将每一个queries[x]放在一个long int数值的高32位,将下标x放在这个long int数值的低32位。 由此,我们可以看出,这些新的long int数值,它们之间的相互大小关系,取决于高32位的数值,只有在高32位相等的时候,才需要比较低32位。如此,我们在比较大小时,优先看高32位,然后想要获取其下标信息时,直接取低32位。 类似的,我们在处理输入的intervals[]数组时也类似处理。将每一个intervals[x]的左边缘放在一个long int数值的高32位,右边缘放在这个long int数值的低32位。这样,这些long int数值,它们之间的相互大小关系,就取决于左边缘的大小关系,而想要获取右边缘时,直接取低32位即可。
  • 小根堆(优先队列):
    • ​​​​​​​ 我们要由小到大处理queries[]数组和intervals[]数组,可以考虑排序,也可以考虑小根堆,这里采用小根堆。

【具体实现】

  1. 将输入的intervals[]数组,每一个intervals[x]的左边缘放在一个long int数值的高32位,右边缘放在这个long int数组的低32位,然后long int数值push入小根堆intervalsHeap。
  2. 将输入的queries[]数组,每一个queries[x]的数值放在一个long int数值的高32位,下标x放在这个long int数值的低32位,然后long int数值push入小根堆queriesHeap。
  3. 逐个从queriesHeap中pop出堆顶元素,这个堆顶元素的高32位就是上面第2步push入堆时,每一个queries[x]的数值,赋值给变量position,低32位就是下标x。
    1. 3.1 从intervalsHeap中pop出所有左边缘(高32位)小于等于position的区间。
    2. 3.2 上面3.1中pop出的每一个区间,把所有右边缘(低32位)大于等于position的区间,都push入一个有效区间小根堆validHeap中。这个validHeap中,以区间的range为高32位,右边缘为低32位,以保证堆顶的区间range始终是最小的。
    3. 3.3 如果validHeap堆顶区间的右边缘(低32位)小于当前的position,则将其弹出。
    4. 3.4 经过上面3.3的操作后,如果validHeap仍然非空,则说明存在包含这个position的区间,且validHeap的堆顶区间的range(高32位)就是题目要求的结果。

代码

/* 几个全局定义的说明。INVALID_VALUE:            无效值-1。小根堆中,根节点的父节点使用这个无效值。题目中结果数组里的无效值也是这个-1。FATHER_NODE(x):           小根堆中,每一个节点的父节点。其中,根节点的父节点是无效值。LEFT_NODE(x):             小根堆中,每一个节点的左子节点。当它大于等于堆size的时候无效。RIGHT_NODE(x):            小根堆中,每一个节点的右子节点。当它大于等于堆size的时候无效。MERGE_LONG(x, y):         两个int数值合并成一个long int数值,其中x占据高32位,y占据低32位。GET_HIGHER32(x):          获取一个long int数值的高32位值。GET_LOWER32(x):           获取一个long int数值的低32位值。 */
#define INVALID_VALUE       -1
#define FATHER_NODE(x)      ((0 == (x)) ? INVALID_VALUE : ((x) - 1 >> 1))
#define LEFT_NODE(x)        (((x) << 1) + 1)
#define RIGHT_NODE(x)       (((x) << 1) + 2)
#define MERGE_LONG(x, y)    ((long int)(x) << 32 | (long int)(y))
#define GET_HIGHER32(x)     ((x) >> 32)
#define GET_LOWER32(x)      ((x) & 0xFFFFFFFF)/* 小根堆的结构定义,里面包括堆空间数组arr[],和堆size。 */
typedef struct
{long int *arr;int arrSize;
}
HeapStruct;static void heapPush(HeapStruct *heap, long int t);
static void heapPop(HeapStruct *heap);/* 主函数的几个变量说明:x:                循环下标。position:         queries数组中的数值。因为这个数组会带着下标一起入堆,在出堆时,把它的实际数值取出到这个position。range:            题目中定义的一个左闭右闭区间的大小,等于“右边缘 - 左边缘 + 1”。t:                long int临时数值。arr1,arr2,arr3:   几个小根堆中要用到的堆空间数组。intervalsHeap:    将输入的intervals数组加入到这个小根堆中,左边缘放高32位,右边缘放低32位。queriesHeap:      将输入的queries数组加入到这个小根堆中,数值放高32位,下标放低32位。validHeap:        包含着当前position的有效区间的小根堆,区间range放高32位,右边缘放低32位。 */
int *minInterval(int **intervals, int intervalsSize, int *intervalsColSize, int *queries, int queriesSize, int *returnSize)
{int x = 0, position = 0, range = 0;long int t = 0;long int arr1[intervalsSize], arr2[queriesSize], arr3[intervalsSize];HeapStruct intervalsHeap, queriesHeap, validHeap;int *result = NULL;/* 申请结果数组的内存空间。 */result = (int *)malloc(sizeof(int) * queriesSize);if(NULL == result){*returnSize = 0;return result;}/* 堆空间定义,初始化一开始堆都为空。 */intervalsHeap.arr = arr1;intervalsHeap.arrSize = 0;queriesHeap.arr = arr2;queriesHeap.arrSize = 0;validHeap.arr = arr3;validHeap.arrSize = 0;/* 把所有的区间放入堆中,左边缘为高优先级,右边缘为低优先级。 */while(intervalsSize > x){t = MERGE_LONG(intervals[x][0], intervals[x][1]);heapPush(&intervalsHeap, t);x++;}/* 把所有的查询放入堆中,位置为高优先级,下标为低优先级。 */x = 0;while(queriesSize > x){t = MERGE_LONG(queries[x], x);heapPush(&queriesHeap, t);x++;}/* 一个个查询逐个出堆。 */while(0 < queriesHeap.arrSize){/* 把下标和位置列出,然后出堆。 */x = GET_LOWER32(queriesHeap.arr[0]);position = GET_HIGHER32(queriesHeap.arr[0]);heapPop(&queriesHeap);/* 把所有左边缘小于等于position的区间弹出。 */while(0 < intervalsHeap.arrSize && position >= GET_HIGHER32(intervalsHeap.arr[0])){/* 右边缘大于等于position的区间放到有效堆中(右边缘小于position的不可能包含当前position)。这个有效堆以range为第一优先级,确保堆顶的区间是range最小的。 */if(position <= GET_LOWER32(intervalsHeap.arr[0])){range = GET_LOWER32(intervalsHeap.arr[0]) - GET_HIGHER32(intervalsHeap.arr[0]) + 1;t = MERGE_LONG(range, GET_LOWER32(intervalsHeap.arr[0]));heapPush(&validHeap, t);}heapPop(&intervalsHeap);}/* 有效堆中,如果堆顶的右边缘小于position,则弹出。这里用到了延迟删除的思想。因为最小堆的pop操作只能针对堆顶。上面对validHeap进行push操作之后,堆顶的区间右边缘值可能已经小于当前的位置了,这种情况必须pop出去。 */while(0 < validHeap.arrSize && position > GET_LOWER32(validHeap.arr[0])){heapPop(&validHeap);}/* 如果此时的有效堆非空,则当前查询的取值就是堆顶的区间大小,否则就是题目要求的-1。 */result[x] = (0 < validHeap.arrSize) ? GET_HIGHER32(validHeap.arr[0]) : INVALID_VALUE;}/* 返回数组长度等于queriesSize。 */*returnSize = queriesSize;return result;
}/* 小根堆的push操作。
为确保其保持为一棵完整二叉树,新push入的数值初始放到堆尾,然后,根据父子节点的大小关系调整位置。 */
static void heapPush(HeapStruct *heap, long int t)
{int son = heap->arrSize, father = FATHER_NODE(son);heap->arrSize++;while(INVALID_VALUE != father && heap->arr[father] > t){heap->arr[son] = heap->arr[father];son = father;father = FATHER_NODE(son);}heap->arr[son] = t;return;
}/* 小根堆的pop操作。
堆顶弹出后,堆顶空缺,为确保其保持为一棵完整二叉树,将堆尾的数值补充到堆顶,然后,根据父子节点的大小关系调整位置。 */
static void heapPop(HeapStruct *heap)
{int father = 0, left = LEFT_NODE(father), right = RIGHT_NODE(father), son = 0;long int t = heap->arr[heap->arrSize - 1];heap->arrSize--;while((heap->arrSize > left && heap->arr[left] < t)|| (heap->arrSize > right && heap->arr[right] < t)){son = (heap->arrSize > right && heap->arr[right] < heap->arr[left]) ? right : left;heap->arr[father] = heap->arr[son];father = son;left = LEFT_NODE(father);right = RIGHT_NODE(father);}heap->arr[father] = t;return;
}作者:恒等式
链接:https://leetcode.cn/problems/minimum-interval-to-include-each-query/solutions/2026632/bao-han-mei-ge-cha-xun-de-zui-xiao-qu-ji-lxkj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。/* 几个全局定义的说明。INVALID_VALUE:            无效值-1。小根堆中,根节点的父节点使用这个无效值。题目中结果数组里的无效值也是这个-1。FATHER_NODE(x):           小根堆中,每一个节点的父节点。其中,根节点的父节点是无效值。LEFT_NODE(x):             小根堆中,每一个节点的左子节点。当它大于等于堆size的时候无效。RIGHT_NODE(x):            小根堆中,每一个节点的右子节点。当它大于等于堆size的时候无效。MERGE_LONG(x, y):         两个int数值合并成一个long int数值,其中x占据高32位,y占据低32位。GET_HIGHER32(x):          获取一个long int数值的高32位值。GET_LOWER32(x):           获取一个long int数值的低32位值。 */
#define INVALID_VALUE       -1
#define FATHER_NODE(x)      ((0 == (x)) ? INVALID_VALUE : ((x) - 1 >> 1))
#define LEFT_NODE(x)        (((x) << 1) + 1)
#define RIGHT_NODE(x)       (((x) << 1) + 2)
#define MERGE_LONG(x, y)    ((long int)(x) << 32 | (long int)(y))
#define GET_HIGHER32(x)     ((x) >> 32)
#define GET_LOWER32(x)      ((x) & 0xFFFFFFFF)/* 小根堆的结构定义,里面包括堆空间数组arr[],和堆size。 */
typedef struct
{long int *arr;int arrSize;
}
HeapStruct;static void heapPush(HeapStruct *heap, long int t);
static void heapPop(HeapStruct *heap);/* 主函数的几个变量说明:x:                循环下标。position:         queries数组中的数值。因为这个数组会带着下标一起入堆,在出堆时,把它的实际数值取出到这个position。range:            题目中定义的一个左闭右闭区间的大小,等于“右边缘 - 左边缘 + 1”。t:                long int临时数值。arr1,arr2,arr3:   几个小根堆中要用到的堆空间数组。intervalsHeap:    将输入的intervals数组加入到这个小根堆中,左边缘放高32位,右边缘放低32位。queriesHeap:      将输入的queries数组加入到这个小根堆中,数值放高32位,下标放低32位。validHeap:        包含着当前position的有效区间的小根堆,区间range放高32位,右边缘放低32位。 */
int *minInterval(int **intervals, int intervalsSize, int *intervalsColSize, int *queries, int queriesSize, int *returnSize)
{int x = 0, position = 0, range = 0;long int t = 0;long int arr1[intervalsSize], arr2[queriesSize], arr3[intervalsSize];HeapStruct intervalsHeap, queriesHeap, validHeap;int *result = NULL;/* 申请结果数组的内存空间。 */result = (int *)malloc(sizeof(int) * queriesSize);if(NULL == result){*returnSize = 0;return result;}/* 堆空间定义,初始化一开始堆都为空。 */intervalsHeap.arr = arr1;intervalsHeap.arrSize = 0;queriesHeap.arr = arr2;queriesHeap.arrSize = 0;validHeap.arr = arr3;validHeap.arrSize = 0;/* 把所有的区间放入堆中,左边缘为高优先级,右边缘为低优先级。 */while(intervalsSize > x){t = MERGE_LONG(intervals[x][0], intervals[x][1]);heapPush(&intervalsHeap, t);x++;}/* 把所有的查询放入堆中,位置为高优先级,下标为低优先级。 */x = 0;while(queriesSize > x){t = MERGE_LONG(queries[x], x);heapPush(&queriesHeap, t);x++;}/* 一个个查询逐个出堆。 */while(0 < queriesHeap.arrSize){/* 把下标和位置列出,然后出堆。 */x = GET_LOWER32(queriesHeap.arr[0]);position = GET_HIGHER32(queriesHeap.arr[0]);heapPop(&queriesHeap);/* 把所有左边缘小于等于position的区间弹出。 */while(0 < intervalsHeap.arrSize && position >= GET_HIGHER32(intervalsHeap.arr[0])){/* 右边缘大于等于position的区间放到有效堆中(右边缘小于position的不可能包含当前position)。这个有效堆以range为第一优先级,确保堆顶的区间是range最小的。 */if(position <= GET_LOWER32(intervalsHeap.arr[0])){range = GET_LOWER32(intervalsHeap.arr[0]) - GET_HIGHER32(intervalsHeap.arr[0]) + 1;t = MERGE_LONG(range, GET_LOWER32(intervalsHeap.arr[0]));heapPush(&validHeap, t);}heapPop(&intervalsHeap);}/* 有效堆中,如果堆顶的右边缘小于position,则弹出。这里用到了延迟删除的思想。因为最小堆的pop操作只能针对堆顶。上面对validHeap进行push操作之后,堆顶的区间右边缘值可能已经小于当前的位置了,这种情况必须pop出去。 */while(0 < validHeap.arrSize && position > GET_LOWER32(validHeap.arr[0])){heapPop(&validHeap);}/* 如果此时的有效堆非空,则当前查询的取值就是堆顶的区间大小,否则就是题目要求的-1。 */result[x] = (0 < validHeap.arrSize) ? GET_HIGHER32(validHeap.arr[0]) : INVALID_VALUE;}/* 返回数组长度等于queriesSize。 */*returnSize = queriesSize;return result;
}/* 小根堆的push操作。
为确保其保持为一棵完整二叉树,新push入的数值初始放到堆尾,然后,根据父子节点的大小关系调整位置。 */
static void heapPush(HeapStruct *heap, long int t)
{int son = heap->arrSize, father = FATHER_NODE(son);heap->arrSize++;while(INVALID_VALUE != father && heap->arr[father] > t){heap->arr[son] = heap->arr[father];son = father;father = FATHER_NODE(son);}heap->arr[son] = t;return;
}/* 小根堆的pop操作。
堆顶弹出后,堆顶空缺,为确保其保持为一棵完整二叉树,将堆尾的数值补充到堆顶,然后,根据父子节点的大小关系调整位置。 */
static void heapPop(HeapStruct *heap)
{int father = 0, left = LEFT_NODE(father), right = RIGHT_NODE(father), son = 0;long int t = heap->arr[heap->arrSize - 1];heap->arrSize--;while((heap->arrSize > left && heap->arr[left] < t)|| (heap->arrSize > right && heap->arr[right] < t)){son = (heap->arrSize > right && heap->arr[right] < heap->arr[left]) ? right : left;heap->arr[father] = heap->arr[son];father = son;left = LEFT_NODE(father);right = RIGHT_NODE(father);}heap->arr[father] = t;return;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/4808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ceph 服务的运用

目录 一、资源池 pool 管理 1.创建一个 Pool 资源池 2.查看集群 Pool 信息 3.查看资源池副本的数量 4.查看 PG 和 PGP 数量 5.修改 pg_num 和 pgp_num 的数量为 128 6.修改 Pool 副本数量为 2 7.修改默认副本数为 2 8.删除 Pool 资源池 8.1修改配置文件 8.2推送 ceph…

TypeScript 1 - 小记

文章目录 关于 TypeScript 关于 TypeScript TypeScript is a superset of JavaScript that compiles to clean JavaScript output. 官网&#xff1a;https://www.typescriptlang.orggithub : https://github.com/microsoft/TypeScriptplayground : https://www.typescriptlan…

BTP Integration Suite学习笔记 - (Unit3) Developing with SAP Integration Suite

BTP Integration Suite学习笔记 - (Unit1) Developing with SAP Integration Suite BTP Integration Suite学习笔记 - (Unit2) Developing with SAP Integration Suite 带着一个问题去学&#xff1a;明明可以直接访问一个后端系统的OData服务&#xff0c;为什么还要再多绕一道C…

Linux5.16 Ceph集群

文章目录 计算机系统5G云计算第四章 LINUX Ceph集群一、Ceph1.存储基础1&#xff09;单机存储设备2&#xff09;单机存储的问题3&#xff09;商业存储解决方案4&#xff09;分布式存储&#xff08;软件定义的存储 SDS&#xff09;5&#xff09;分布式存储的类型 2.Ceph 简介3.C…

获得servlet相关API,获得请求头和cookie-spring23

后台能够成功打印 如何获得请求头 如何获得cookie 获取浏览器信息 把network下user Agent的值赋给他 这个值可以直接赋给Cookie 就是这个cookie 把cookie的值赋值给一边JasonId&#xff0c; 这里面的Value代表着名字,名字是cookie后面那一块&#xff1a;

nginx推流环境搭建

目录 1、创建安装文件夹2、安装编译 nginx 所需要的库3、下载 nginx-1.21.6.tar.gz下载 nginx-rtmp-module4、解压解压nginx文件解压rtmp模块5、编译6、安装7、启动nginx,检测nginx是否能成功运行8、配置nginx使用RTMP9、重启nginx服务器1、创建安装文件夹 cd ~ mkdir nginx …

Comparator.comparing()实现中文排序及空指针处理

一、 Comparator.comparing()的用法请详见以下上一篇文章的汇总介绍。 Comparator用法_乞力马扎罗の黎明的博客-CSDN博客 二、应用示例&#xff1a; 1、中文排序、空值处理 Collator instance Collator.getInstance(Locale.CHINA); checkItemVoList.stream().sorted(Compar…

每日科技分享-POE新增文件和链接发送功能

POE推出新功能 注意POE需要魔法上午才能进去。 实测 实测可以发送论文给chatgpt&#xff0c;然后和AI进行共享的对话。 POE网站链接&#xff1a; 也可以发送链接&#xff0c;实测了一下&#xff0c;似乎有时候并不准确&#xff0c;我发送了关于分层强化的文章&#xff0c;但是…

<数据结构>NO11.归并排序|递归|非递归|优化

文章目录 归并排序递归写法非递归写法修正方案1.归并一段拷贝一段修正方案2.修正区间 算法优化算法分析 归并排序的应用外排序和内排序 归并排序 递归写法 思路: 如果给出两个有序数组&#xff0c;我们很容易可以将它们合并为一个有序数组。因此当给出一个无序数组时&#xf…

华为无线ac+ap旁挂二层组网常用配置案例

AC控制器理解配置步骤&#xff1a; capwap source interface Vlanif 100 //源IP回包地址 wlan ssid-profile name test //新建个模版名称为test ssid test //wifi名称 wlan security-profile name test //建立安全模版也叫test security wpa-wpa2 psk pass-phrase admin123 a…

linux 安装 cuda

需求&#xff1a; inux 下安装 cuda 进程&#xff1a; 先查看一下系统版本 uname -a查看能支持什么版本的cudacuda toolkit 下载 wget https://developer.download.nvidia.com/compute/cuda/11.1.0/local_installers/cuda_11.1.0_455.23.05_linux.run sudo sh cuda_11.1.0_4…

API 接口是什么?怎么对接 API?

一、API接口是什么&#xff1f; API接口即应用编程接口&#xff0c;是一些预先定义的函数&#xff0c;可以提供应用程序与开发人员基于某软件或硬件以访问一组例程的能力。简单来说&#xff0c;API接口相当于信息的桥梁&#xff0c;它可以让不同平台、应用程序或系统共享数据&…

对Element DatePicker时间组件的封装,时间组件开始时间和结束时间绑定

背景 我们时常有时间范围选择&#xff0c;需要选择一个开始时间和一个结束时间给后端&#xff0c;但我们给后端的是两个字段&#xff0c; 分别是开始时间和结束时间&#xff0c;现在使用element绑定的值是一个数组&#xff0c;我们还要来回处理&#xff0c;很麻烦列表也的查询…

JAVA集成国密SM2

JAVA集成国密SM2加解密 一、pom配置二、代码集成2.1、目录结构2.2、源码2.3、测试 三、相关链接 国密算法概述&#xff1a;https://blog.csdn.net/qq_38254635/article/details/131801527 SM2椭圆曲线公钥密码算法 为非对称加密&#xff0c;基于ECC。该算法已公开。由于该算法…

react使用SVGA特效 常用api

下载插件 npm install svgaplayerweb --save react中代码 import React, { useEffect } from react; import SVGA from svgaplayerweb const Svga () > {const bofang () > {var player new SVGA.Player(#demoCanvas);//创建实例var parser new SVGA.Parser(#demo…

centos7安装 mongodb

一、rpm安装 1.1、配置MongoDB Enterprise的yum 源文件 [mongodb-enterprise] nameMongoDB Enterprise Repository baseurlhttps://repo.mongodb.com/yum/redhat/$releasever/mongodb-enterprise/3.4/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://www.mongodb.org/static/pgp…

【Maven三】——maven生命周期和插件

系列文章目录 Maven之POM介绍 maven命令上传jar包到nexus 【Maven二】——maven仓库 maven生命周期和插件 系列文章目录前言一、什么是生命周期&why1.三套生命周期2.clean生命周期3.default生命周期4.site生命周期5.命令行与生命周期 二、插件目标三、插件绑定1.内置绑定2…

libevent:windows环境配置+QT使用

目录 libevent是什么 编译 QT使用 测试代码 libevent是什么 Fast portable non-blocking network programming with Libevent http://www.wangafu.net/~nickm/libevent-book/TOC.html 这篇文档讲的很清楚&#xff0c;尤其是Chapter 1: A tiny introduction to asynchro…

matlab入门

命名规则&#xff1a; clc&#xff1a;清除命令行的所有命令 clear all&#xff1a;清除所有工作区的内容 注释&#xff1a;两个% 空格 %% matlab的数据类型 1、数字 3 3 * 5 3 / 5 3 5 3 - 52、字符与字符串 s a %% 求s的ascill码 abs(s) char(97) num2str(65) str I…

家政小程序开发-H5+小程序

移动互联网的发展&#xff0c;微信小程序逐渐成为商家拓展线上业务的重要手段。家政服务作为日常生活中不可或缺的一部分&#xff0c;也开始尝试通过小程序来提高服务质量和效率。 下面是一篇关于家政小程序开发的H5小程序的文章&#xff0c;希望对您有所帮助。 家政服…