LeetCode 436. Find Right Interval【排序,二分;双指针,莫队】中等

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你一个区间数组 intervals ,其中 intervals[i] = [starti, endi] ,且每个 starti 都 不同 。

区间 i 的 右侧区间 可以记作区间 j ,并满足 startj >= endi ,且 startj 最小化 。注意 i 可能等于 j 。

返回一个由每个区间 i 的 右侧区间 在 intervals 中对应下标组成的数组。如果某个区间 i 不存在对应的 右侧区间 ,则下标 i 处的值设为 -1 。

示例 1:

输入:intervals = [[1,2]]
输出:[-1]
解释:集合中只有一个区间,所以输出-1

示例 2:

输入:intervals = [[3,4],[2,3],[1,2]]
输出:[-1,0,1]
解释:对于 [3,4] ,没有满足条件的“右侧”区间。
对于 [2,3] ,区间[3,4]具有最小的“右”起点;
对于 [1,2] ,区间[2,3]具有最小的“右”起点。

示例 3:

输入:intervals = [[1,4],[2,3],[3,4]]
输出:[-1,2,-1]
解释:对于区间 [1,4][3,4] ,没有满足条件的“右侧”区间。
对于 [2,3] ,区间 [3,4] 有最小的“右”起点。

提示:

  • 1 <= intervals.length <= 2 * 10^4
  • intervals[i].length == 2
  • -10^6 <= starti <= endi <= 10^6
  • 每个间隔的起点都 不相同

解法1 排序+二分

最简单的解决方案是对于集合中的每个区间,我们扫描所有区间找到其起点大于当前区间的终点的区间(具有最小差值),时间复杂度为 O ( n 2 ) O(n^2) O(n2) ,在此不详细描述。

对于一个特定的 i t s [ i ] its[i] its[i] 而言,其右端点固定,并且我们只关心目标位置的左端点

  1. 首先将每个 i t s [ i ] [ 0 ] its[i][0] its[i][0] 与其对应的索引 i i i 存储在数组 i t s S t a r t itsStart itsStart 中,并对其按 i t s [ i ] [ 0 ] its[i][0] its[i][0] 的大小进行排序
  2. 然后枚举每个区间 i t s [ i ] its[i] its[i] 的右端点 i t s [ i ] [ 1 ] its[i][1] its[i][1],利用二分查找在 i t s S t a r t itsStart itsStart 中找到大于等于 i t s [ i ] [ 1 ] its[i][1] its[i][1] 的最小值 v a l val val ,此时区间 i t s [ i ] its[i] its[i] 对应的右侧区间即为 v a l val val 对应的索引
class Solution {
public:vector<int> findRightInterval(vector<vector<int>>& intervals) {int n = intervals.size();vector<pair<int, int>> itsStart;for (int i = 0; i < n; ++i) itsStart.emplace_back(intervals[i][0], i);sort(itsStart.begin(), itsStart.end());vector<int> ans(n);for (int i = 0; i < n; ++i) {int l = 0, r = n;while (l < r) {int mid = (l + r) >> 1;if (itsStart[mid].first >= intervals[i][1]) r = mid;else l = mid + 1;}ans[i] = l == n ? -1 : itsStart[l].second;}return ans;}
};

复杂度分析:

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 为区间数组的长度。排序的时间为 O ( n log ⁡ n ) O(n \log n) O(nlogn),每次进行二分查找花费的时间为 O ( log ⁡ n ) O(\log n) O(logn),一共需要进行 n n n 次二分查找,因此总的时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)
  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 为区间数组的长度。 i t s S t a r t itsStart itsStart 一共存储了 n n n 个元素,因此空间复杂度为 O ( n ) O(n) O(n)

解法2 排序+双指针(莫队思想)

更进一步,在解法一中我们并没有对求解询问的顺序进行调整,这导致了我们不得不每次都在整个左端点序列中进行二分。朴素处理询问的方式,需要每次对整个序列进行双重扫描,复杂度为 O ( n 2 ) O(n^2) O(n2)

但实际上,如果我们按照「右端点从小到大」的顺序处理询问,其每个询问对应的「最右区间的左端点」也具有单调特性。具体进行说明。

开辟两个新的数组:

  • s t a r t I n t e r v a l s startIntervals startIntervals,基于所有区间的起始点和下标从小到大排序。
  • e n d I n t e r v a l s endIntervals endIntervals,基于所有区间的结束点和下标从小到大排序。

我们从 e n d I n t e r v a l s endIntervals endIntervals 数组中取出第 i i i 个区间,从左到右扫描 s t a r t I n t e r v a l s startIntervals startIntervals 数组中的区间起点来找到满足右区间条件的区间。设 e n d I n t e r v a l s endIntervals endIntervals 数组中第 i i i 个元素的右区间为 s t a r t I n t e r v a l s startIntervals startIntervals 数组中的第 j j j 个元素,此时可以知道:
startIntervals [ j − 1 ] [ 0 ] < endIntervals [ i ] [ 0 ] , startIntervals [ j ] [ 0 ] ≥ endIntervals [ i ] [ 0 ] \begin{aligned} \textit{startIntervals}[j-1][0] < \textit{endIntervals}[i][0],\\ \textit{startIntervals}[j][0] \ge \textit{endIntervals}[i][0] \end{aligned} startIntervals[j1][0]<endIntervals[i][0],startIntervals[j][0]endIntervals[i][0]

当我们遍历 e n d I n t e r v a l s endIntervals endIntervals 数组中第 i + 1 i+1 i+1 个元素时,不需要从第一个索引开始扫描 s t a r t I n t e r v a l s startIntervals startIntervals 数组,可以直接从第 j j j 个元素开始扫描 s t a r t I n t e r v a l s startIntervals startIntervals 数组。由于数组中所有的元素都是已排序,因此可以知道
startIntervals [ j − 1 ] [ 0 ] < endIntervals [ i ] [ 0 ] ≤ endIntervals [ i + 1 ] [ 1 ] \textit{startIntervals}[j-1][0] < \textit{endIntervals}[i][0] \le \textit{endIntervals}[i+1][1] startIntervals[j1][0]<endIntervals[i][0]endIntervals[i+1][1]
所以数组 s t a r t I n t e r v a l s startIntervals startIntervals 的前 j − 1 j−1 j1 的元素的起始点都小于 e n d I n t e r v a l s [ i + 1 ] [ 1 ] endIntervals[i+1][1] endIntervals[i+1][1] ,因此可以直接跳过前 j − 1 j-1 j1 个元素,只需要从 j j j 开始搜索即可

因此,我们可以运用莫队思想:通过调整询问的处理顺序,来减少扫描目标位置的指针移动次数。将其从「必然进行 n 2 n^2 n2 次移动」优化为「最多不超过 n n n 次移动」,从而将 构造答案 的复杂度从 O ( n 2 ) O(n^2) O(n2) 优化为 O ( n ) O(n) O(n)

最后,由于每个 i n t e r v a l s [ i ] intervals[i] intervals[i] 只关心目标位置的「左端点」,因此我们无须对某一端进行分块,而直接使用双指针实现即可。

class Solution {
public:vector<int> findRightInterval(vector<vector<int>>& intervals) {vector<pair<int, int>> startIntervals;vector<pair<int, int>> endIntervals;int n = intervals.size();for (int i = 0; i < n; i++) {startIntervals.emplace_back(intervals[i][0], i);endIntervals.emplace_back(intervals[i][1], i);}sort(startIntervals.begin(), startIntervals.end());sort(endIntervals.begin(), endIntervals.end());vector<int> ans(n, -1);for (int i = 0, j = 0; i < n && j < n; i++) {while (j < n && endIntervals[i].first > startIntervals[j].first)j++;if (j < n)ans[endIntervals[i].second] = startIntervals[j].second;}return ans;}
};

复杂度分析:

  • 时间复杂度:排序复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn) ;双指针构造答案的复杂度为 O ( n ) O(n) O(n) 。整体复杂度为 O ( n log ⁡ n ) O(n\log{n}) O(nlogn)
  • 空间复杂度: O ( n ) O(n) O(n)

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

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

相关文章

perl GetOptions

在Perl中&#xff0c;你可以使用标准模块Getopt::Long来解析命令行选项&#xff08;Command Line Options&#xff09;。Getopt::Long模块允许你定义命令行选项以及它们的值&#xff0c;并且还可以处理各种类型的选项&#xff0c;如标志选项&#xff08;flag options&#xff0…

算法竞赛入门【码蹄集新手村600题】(MT1060-1080)

算法竞赛入门【码蹄集新手村600题】(MT1060-1080&#xff09; 目录MT1061 圆锥体的体积MT1062 圆锥体表面积MT1063 立方体的体积MT1064 立方体的表面积MT1065 长方体的表面积MT1066 射线MT1067 线段MT1068 直线切平面MT1069 圆切平面MT1070 随机数的游戏MT1071 计算表达式的值M…

网络防御之IDS

1. 什么是IDS&#xff1f; IDS是入侵检测系统&#xff0c;一种对于网络传输进行及时监视&#xff0c;在发现可疑的传输时发出警报或者采取主动反应措施的网络安全设备。IDS是一种积极地主动的防御技术。 2. IDS和防火墙有什么不同&#xff1f; 防火墙是一种隔离并过滤非授权用…

Leetcode-每日一题【剑指 Offer II 075. 数组相对排序】

题目 给定两个数组&#xff0c;arr1 和 arr2&#xff0c; arr2 中的元素各不相同 arr2 中的每个元素都出现在 arr1 中 对 arr1 中的元素进行排序&#xff0c;使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。 示例&…

EtherNet/IP转CAN网关can协议标准

生产管理设备中&#xff0c;会有设备与其他设备的协议不同&#xff0c;数据无法互通&#xff0c;让你的工作陷入困境。这时&#xff0c;一款神奇的产品出现了——远创智控YC-EIP-CAN通讯网关&#xff01; 1, 这款通讯网关采用ETHERNET/IP从站功能&#xff0c;可以将各种CAN总线…

Lambda表达式

Java Lambda表达式是Java 8中最重要的新特性之一。 它们是一种可传递的匿名函数&#xff0c;可以作为参数传递给方法或存储在变量中&#xff0c;因此可以在需要的时候调用它们。 基础 1. 简介 Lambda表达式的主要目的是简化Java代码&#xff0c;使其更易于阅读和编写。 Lam…

【业务功能篇58】Springboot + Spring Security 权限管理 【中篇】

4.2.3 认证 4.2.3.1 什么是认证&#xff08;Authentication&#xff09; 通俗地讲就是验证当前用户的身份&#xff0c;证明“你是你自己”&#xff08;比如&#xff1a;你每天上下班打卡&#xff0c;都需要通过指纹打卡&#xff0c;当你的指纹和系统里录入的指纹相匹配时&…

前端存储之sessionStorage和localStorage

sessionStorage sessionStorage是一种用于web浏览器中临时保存数据的客户端存储机制。它允许在同一个浏览器窗口的会话期间&#xff0c;保存和访问临时数据&#xff0c;而这些数据在用户关闭窗口或者标签页会被清除。每个sessionStorage对象都与当前的浏览器会话相关联&#x…

12.python设计模式【观察者模式】

内容&#xff1a;定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变的时候&#xff0c;所有依赖于它的对象得到通知并被自动更新。观者者模式又称为“发布-订阅”模式。比如天气预报&#xff0c;气象局分发气象数据。 角色&#xff1a; 抽象主题&#xf…

leetcode 122. 买卖股票的最佳时机 II

2023.7.29 把整体利润拆分成每天的利润&#xff0c;将股票值想象成一个折线图&#xff0c;将所有上升的值相加即可。 代码&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int ans 0;for(int i1; i<prices.size(); i){if(prices[i]-…

SpringBoot使用jetty和tomcat还有undertow以及ssl配置支持https请求

一般使用SpringBoot开发应用程序都是使用的tomcat 稍微注意点性能就使用undertow&#xff0c;配置支持https请求常用nginx来做代理&#xff0c;直接用SpringBoot配置还是很少的&#xff0c;八成用不到&#xff0c;就怕需要用到的时候又不能及时弄出来&#xff0c;于是记录一下。…

到底叫 集合还是数组还是list还是列表?

1 总体上可以将数据结构分为数组和集合两种&#xff0c;而列表是一个泛指 数组&#xff1a;在Java中&#xff0c;数组是一种基本数据类型&#xff0c;可以用来存储同一类型的多个元素&#xff0c;数组的长度是固定的。例如&#xff1a;int[] arr new int[10];List&#xff1a…

CenOS设置启动级别

背景知识 init一共分为7个级别&#xff0c;这7个级别的所代表的含义如下 0&#xff1a;停机或者关机&#xff08;千万不能将initdefault设置为0&#xff09;1&#xff1a;单用户模式&#xff0c;只root用户进行维护2&#xff1a;多用户模式&#xff0c;不能使用NFS(Net File S…

第2集丨webpack 江湖 —— 创建一个简单的webpack工程demo

目录 一、创建webpack工程1.1 新建 webpack工程目录1.2 项目初始化1.3 新建src目录和文件1.4 安装jQuery1.5 安装webpack1.6 配置webpack1.6.1 创建配置文件&#xff1a;webpack.config.js1.6.2 配置dev脚本1.7 运行dev脚本 1.8 查看效果1.9 附件1.9.1 package.json1.9.2 webpa…

Redis - Bitmap

什么是Bitmap 操作String数据类型的key所存储的字符串指定偏移量上的位&#xff0c;返回原位置的值优点&#xff1a; 节省空间通过一个bit位来表示某个元素对应的值或者状态&#xff0c;其中key就是对应元素的值。实际上8个bit可以组成一个Byte,所以是及其节省空间的效率高se…

ReactRouterv5在BrowserRouter和HashRouter模式下对location.state的支持

结论&#xff1a;HashRouter不支持location.state 文档&#xff1a;ReactRouter v5 从文档可看到history.push()方法支持2个参数&#xff1a;path, [state] state即是location.state&#xff0c;常用于隐式地传递状态参数 但文档未提的是&#xff0c;仅适用于BrowserRouter&am…

C++-Rust-一次性掌握两门语言

C-Rust-一次性掌握两门语言 简介特色数据类型声明常量、变量判断与循环函数抽象化的对象&#xff1a;类与接口枚举模板与泛型Lambda匿名函数表达式 简介 本文主要是通过介绍C和Rust的基础语法达成极速入门两门开发语言。 C是在C语言的基础之上添加了面向对象的类、重载、模板等…

《面试1v1》Kafka的架构设计是什么样子

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

百度开发者平台API地理编码,根据地址获取经纬度

地理编码 | 百度地图API SDK (baidu.com) 原始csv # encoding:utf-8 import requests import csv import json # 接口地址 url "https://api.map.baidu.com/geocoding/v3"# 此处填写你在控制台-应用管理-创建应用后获取的AK ak "XXXXXXX"# 创建CSV文件并…

04-树6 Complete Binary Search Tree

思路&#xff1a; 先排序 用数组建一棵空树 中序遍历填数 顺序输出即为层次遍历