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…

word页码怎么从第二页开始

视频&#xff1a;https://product.pconline.com.cn/itbk/vedio/1810/11904520.html 1/15 本视频由Office2010进行演示&#xff0c;打开Word 2/15 点击“插入” 3/15 点击“页码” 4/15 选择自己需要的页码位置和格式 5/15 点击“页面布局” 6/15 点击“页面设置” 7/15 点击“…

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…

MACOS查找并解决端口占用

当在Mac上遇到端口占用问题时&#xff0c;可以通过以下步骤解决&#xff1a; 打开终端应用程序&#xff08;Terminal&#xff09;。使用以下命令查找占用特定端口的程序&#xff1a;sudo lsof -n -P | grep :<port>将 <port> 替换为要查找的端口号。例如&#xff…

C语言实现通讯录

今天分享一个通讯录的代码&#xff0c;代码可以正常运行&#xff0c;但是可能有一点点缺陷&#xff0c;完成的是我们的通讯录功能 contact.h #pragma once #include<string.h>#include<stdio.h> #include<assert.h> #define MAX 1000 #define NAME_MAX 20 #…

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;

spring-boot-2.2.13.RELEASE 升级 2.6.6 记录

一、版本升级 spring-boot-2.2.13.RELEASE 升级 2.6.6 <properties>...<spring.boot.version>2.6.6</spring.boot.version><spring-cloud.version>2021.0.1</spring-cloud.version><spring-cloud-alibaba.version>2021.0.1.0</spring-…

librdkafka的rdk:broker-1线程cpu百分百问题分析

问题调用栈&#xff1a; (gdb) bt #0 0x000000000068307c in rd_kafka_q_pop_serve (rkq0x1ff31a0, timeout_ms<optimized out>, versionversionentry0, cb_typecb_typeentryRD_KAFKA_Q_CB_RETURN, callbackcallbackentry0x0, opaqueopaqueentry0x0) at rdkafka_queue.…

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 …

React Hooks

React Hooks basic hooks useStateuseEffectuseContext useState useState接收一个参数&#xff0c;返回的是一个数组&#xff0c;参数表示初始值&#xff0c;数组的第1项就是定义的变量&#xff0c;第2项就是改变变量的方法。 参数可以是基本数据类型&#xff0c;如string…

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…

http和https的区别(面试题)

概念 Http&#xff1a;HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写。HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同&#xff0c; 用于客户端和服务器之间的通信。从WWW服务器传输超文本到本地浏览器的传输协议&#xff0c;它可以…

一个月学通Python(二十):Python制作报表(Web开发)

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍制作报表导出Excel报表导出PDF报表生成前端…

python 写个excle表格数据导入mysql数据的服务

下面是一个使用Python将Excel表格数据导入MySQL数据库的示例代码。需要使用pandas和MySQL Connector库。 pythonimport pandas as pd import mysql.connector# 读取Excel文件 df pd.read_excel(data.xlsx)# 连接MySQL数据库 cnx mysql.connector.connect(useryour_username, …

华为无线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…