LeetCode 731. My Calendar II【设计,有序映射,差分;线段树】中等

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

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

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

实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排。

MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为,  start <= x < end

当三个日程安排有一些时间上的交叉时(例如三个日程安排都在同一时间内),就会产生三重预订。

每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致三重预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。

请按照以下步骤调用MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)

示例:

MyCalendar();
MyCalendar.book(10, 20); // returns true
MyCalendar.book(50, 60); // returns true
MyCalendar.book(10, 40); // returns true
MyCalendar.book(5, 15); // returns false
MyCalendar.book(5, 10); // returns true
MyCalendar.book(25, 55); // returns true
解释:
前两个日程安排可以添加至日历中。 第三个日程安排会导致双重预订,但可以添加至日历中。
第四个日程安排活动(5,15)不能添加至日历中,因为它会导致三重预订。
第五个日程安排(5,10)可以添加至日历中,因为它未使用已经双重预订的时间10。
第六个日程安排(25,55)可以添加至日历中,因为时间 [25,40] 将和第三个日程安排双重预订;
时间 [40,50] 将单独预订,时间 [50,55)将和第二个日程安排双重预订。

提示:

  • 每个测试用例,调用 MyCalendar.book 函数最多不超过 1000次。
  • 调用函数 MyCalendar.book(start, end)时, start 和 end 的取值范围为 [0, 10^9]

解法1 直接遍历

记录下所有已经预定的课程安排区间已经预定过两次的课程安排区间,当我们预定新的区间 [ s t a r t , e n d ) [start, end) [start,end) 时,此时检查当前已经预定过两次的每个日程安排是否与新日程安排冲突。若不冲突,则可以添加新的日程安排。

  • 对于两个区间 [ s 1 , e 1 ) [s_1, e_1) [s1,e1) [ s 2 , e 2 ) [s_2, e_2) [s2,e2) ,如果二者没有交集,则此时应当满足 s 1 ≥ e 2 s_1 \ge e_2 s1e2 或者 s 2 ≥ e 1 s_2 \ge e_1 s2e1 ,这就意味着如果满足 s 1 < e 2 s_1 < e_2 s1<e2 并且 s 2 < e 1 s_2 < e_1 s2<e1
  • 首先检测新加入的区间 [ s t a r t , e n d ) [start, end) [start,end)是否与已经预定过两次的区间有交集,如果没有冲突,则将新加入的区间与已经预定的区间进行检查,求出新增的预定两次的区间。对于两个区间 [ s 1 , e 1 ) [s_1, e_1) [s1,e1) [ s 2 , e 2 ) [s_2,e_2) [s2,e2) ,则他们之间的交集为 [ max ⁡ ( s 1 , s 2 ) , min ⁡ ( e 1 , e 2 ) ) [\max(s_1,s_2), \min(e_1,e_2)) [max(s1,s2),min(e1,e2))
class MyCalendarTwo {
public:MyCalendarTwo() {}bool book(int start, int end) {for (auto &[l, r] : overlaps)if (l < end && start < r) return false;for (auto &[l, r] : booked)if (l < end && start < r)overlaps.emplace_back(max(l, start), min(r, end));booked.emplace_back(start, end);return true;}
private:vector<pair<int, int>> booked;vector<pair<int, int>> overlaps;
};

复杂度分析:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2) ,其中 n n n 表示日程安排的数量。由于每次在进行预订时,都需要遍历所有已经预订的行程安排。
  • 空间复杂度: O ( n ) O(n) O(n) ,其中 n n n 表示日程安排的数量。需要保存所有已经预订的行程。

解法2 差分数组

利用差分数组的思想,每当我们预定一个新的日程安排 [ s t a r t , e n d ) [start, end) [start,end),在 s t a r t start start 计数 c n t [ s t a r t ] cnt[start] cnt[start] 1 1 1 ,表示从 s t a r t start start 预定的数目加 1 1 1 ;从 e n d end end 计数 c n t [ e n d ] cnt[end] cnt[end] 1 1 1 ,表示从 e n d end end 开始预定的数目减 1 1 1 。此时以起点 x x x 开始的预定的数目 book x = ∑ y ≤ x cnt [ y ] \textit{book}_x = \sum_{y \le x}\textit{cnt}[y] bookx=yxcnt[y] ,当我们将 [ s t a r t , e n d ) [start, end) [start,end) 加入后,如果发现存在区间的预定数目大于 2 2 2 时,此时为非法,应去除新加入的区间 [ s t a r t , e n d ) [start, end) [start,end) 。由于本题中 start , end \textit{start}, \textit{end} start,end 数量较大,我们利用 TreeMap \texttt{TreeMap} TreeMap 计数即可。

class MyCalendarTwo {
public:MyCalendarTwo() {}bool book(int start, int end) {int maxBook = 0;++cnt[start];--cnt[end];for (auto &[_, freq] : cnt) {maxBook += freq;if (maxBook > 2) {--cnt[start];++cnt[end];return false;}}return true;}
private:map<int, int> cnt;
};

复杂度分析:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2) ,其中 n n n 为日程安排的数量。每次求的最大的预定需要遍历所有的日程安排。
  • 空间复杂度: O ( n ) O(n) O(n) ,其中 n n n 为日程安排的数量。需要空间存储所有的日程安排计数,需要的空间为 O ( n ) O(n) O(n)

解法3 线段树

利用线段树,假设我们开辟了数组 arr [ 0 , ⋯ , 1 0 9 ] \textit{arr}[0,\cdots, 10^9] arr[0,,109] ,初始时每个元素的值都为 0 0 0 ,对于每次行程预定的区间 [ s t a r t , e n d ) [start, end) [start,end) ,则我们将区间中的元素 arr [ start , ⋯ , end − 1 ] \textit{arr}[\textit{start},\cdots,\textit{end}-1] arr[start,,end1] 中的每个元素加 1 1 1 ,如果数组 a r r arr arr 的最大元素大于 2 2 2 时,此时则出现某个区间被安排了 2 2 2 次上,此时返回 false \texttt{false} false ,同时将数组区间 arr [ start , ⋯ , end − 1 ] \textit{arr}[\textit{start},\cdots,\textit{end}-1] arr[start,,end1] 进行减 1 1 1 即可恢复。

实际我们不必实际开辟数组 arr \textit{arr} arr可采用动态线段树懒标记 lazy \textit{lazy} lazy 标记区间 [ l , r ] [l,r] [l,r] 进行累加的次数 tree \textit{tree} tree 记录区间 [ l , r ] [l,r] [l,r]最大值,每次动态更新线段树即可。

class MyCalendarTwo {
public:MyCalendarTwo() {}void update(int s, int e, int val, int l, int r, int idx) {if (r < s || l > e) return;if (s <= l && r <= e) {tree[idx].first += val;tree[idx].second += val;} else {int mid = (l + r) >> 1;update(s, e, val, l, mid, 2 * idx);update(s, e, val, mid + 1, r, 2 * idx + 1);tree[idx].first = tree[idx].second + max(tree[2 * idx].first, tree[2 * idx + 1].first);}}    bool book(int start, int end) {update(start, end - 1, 1, 0, 1e9, 1);if (tree[1].first > 2) {update(start, end - 1, -1, 0, 1e9, 1);return false;}return true;}
private:unordered_map<int, pair<int, int>> tree;
};

复杂度分析:

  • 时间复杂度: O ( n log ⁡ C ) O(n \log C) O(nlogC) ,其中 n n n 为日程安排的数量。由于使用了线段树查询,线段树的最大深度为 log ⁡ C \log C logC ,每次最多会查询 log ⁡ C \log C logC 个节点,每次求最大的预定需的时间复杂度为 O ( log ⁡ C + log ⁡ C ) O(\log C + \log C) O(logC+logC) ,因此时间复杂度为 O ( n log ⁡ C ) O(n \log C) O(nlogC) ,在此 C C C 取固定值即为 1 0 9 10^9 109
  • 空间复杂度: O ( n log ⁡ C ) O(n \log C) O(nlogC) ,其中 n n n 为日程安排的数量。由于该解法采用的为动态线段树,线段树的最大深度为 log ⁡ C \log C logC ,每次预定最多会在线段树上增加 log ⁡ C \log C logC 个节点,因此空间复杂度为 O ( n log ⁡ C ) O(n \log C) O(nlogC) ,在此 C C C 取固定值即为 1 0 9 10^9 109

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

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

相关文章

剑指 Offer 07. 重建二叉树

题目描述 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 解题思路 首先&#xff0c;根据前序遍历结果确定根节点。前序遍历的第一个元素即为根节点的值。 接下来&#xff0c…

第17节-PhotoShop基础课程-画笔修复工具

文章目录 前言1.画笔工具1.基本操作2.工具选项1.不透明度2.流量3.平滑2.画笔大小工具栏大小设置 4.笔刷 2.铅笔工具3.颜色替换工具 批量替换颜色4.混合器画笔工具-人像精修 前言 画笔工具的使用 1.画笔工具 1.基本操作 画画 2.工具选项 1.不透明度 2.流量 设置低了会有间隔&…

第29节-PhotoShop基础课程-滤镜库

文章目录 前言1.滤镜库2.Camera Raw滤镜 &#xff08;用来对图片进行预处理&#xff0c;最全面的一个&#xff09;3.神经滤镜&#xff08;2022插件 需要先下载&#xff09;4.液化&#xff08;胖-> 瘦 矮->高&#xff09;5.其它滤镜1.自适应广角2.镜头矫正 把图片放正3.消…

Kafka详解

目录 一、消息系统 1、点对点的消息系统 2、发布-订阅消息系统 二、Apache Kafka 简介 三、Apache Kafka基本原理 3.1 分布式和分区&#xff08;distributed、partitioned&#xff09; 3.2 副本&#xff08;replicated &#xff09; 3.3 整体数据流程 3.4 消息传送机制…

通过jr-qrcode生成二维码并下载到客户端本地(Vue)

生成二维码 首先生成二维码图片的地址 引入jr-qrcode import jrQrcode from jr-qrcode; 生成二维码图片的地址 // 生成二维码地址 getQRCodeUrl(spreadUrl) {const QRCodeUrl jrQrcode.getQrBase64(spreadUrl);return QRCodeUrl; }that.backUrl jrQrcode.getQrBase64(da…

JP《乡村振兴振兴战略下传统村落文化旅游设计》许少辉书香续,山水长

JP《乡村振兴振兴战略下传统村落文化旅游设计》许少辉书香续&#xff0c;山水长

Vue2+Vue3基础入门到实战项目(前接六 副线一)—— 面经 项目

day1 接口文档地址&#xff1a;https://www.apifox.cn/apidoc/project-934563/api-20384515 一、项目功能演示 1.目标 启动准备好的代码&#xff0c;演示移动端面经内容&#xff0c;明确功能模块 2.项目收获 二、项目创建目录初始化 vue-cli 建项目 1.安装脚手架 (已安装…

Python的sort()与sorted()函数详解

目录 sort&#xff08;&#xff09;函数 sorted&#xff08;&#xff09;函数 key参数 区别 sort&#xff08;&#xff09;函数 sort()方法&#xff1a;该方法用于原地对列表进行排序&#xff0c;即直接在原始列表上进行排序操作&#xff0c;并不返回一个新的列表。 my_l…

MySQL MHA

什么是 MHA MHA&#xff08;Master High Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件 MHA 的出现就是解决MySQL 单点故障的问题 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作 MHA能在故障切换的过程中最大程度上…

WebSocket的那些事(5-Spring STOMP支持之连接外部消息代理)

目录 一、序言二、开启RabbitMQ外部消息代理三、代码示例1、Maven依赖项2、相关实体3、自定义用户认证拦截器4、Websocket外部消息代理配置5、ChatController6、前端页面chat.html 四、测试示例1、群聊、私聊、后台定时推送测试2、登录RabbitMQ控制台查看队列信息 五、结语 一、…

第4章_瑞萨MCU零基础入门系列教程之瑞萨 MCU 源码设计规范

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

uniApp监听左右滑动事件

监听左右滑动事件的步骤 1. 添加需要监听滑动事件的元素 在你的页面中&#xff0c;添加需要监听滑动事件的元素。这可以是一个 view、swiper 或其他组件&#xff0c;取决于你的需求。例如&#xff1a; <template><view class"body" touchstart"touc…

deepin V23通过flathub安装steam畅玩游戏

deepin V23缺少32位库&#xff0c;在星火商店安装的steam,打开报错&#xff0c;无法使用&#xff01; 通过flathub网站安装steam,可以正常使用&#xff0c;详细教程如下&#xff1a; flathub网址&#xff1a;主页 | Flathub 注意&#xff1a;flathub下载速度慢&#xff0c;只…

Redis从基础到进阶篇(四)----性能调优、分布式锁与缓存问题

目录 一、Redis 集群演变 1.1 ReplicationSentinel*高可用 1.2 ProxyReplicationSentinel(仅仅了解) 1.3 Redis Cluster 集群 (重点&#xff09; 1.3.1 Redis-cluster架构图 1.3.2 工作原理 1.3.3 主从切换 1.3.4 副本漂移 1.3.5 分片漂移 二、Redis版本历史&#xf…

ODC现已开源:与开发者共创企业级的数据库协同开发工具

OceanBase 开发者中心&#xff08;OceanBase Developer Center&#xff0c;以下简称 ODC&#xff09;是一款开源的数据库开发和数据库管理协同工具&#xff0c;从首个版本上线距今已经发展了三年有余&#xff0c;ODC 逐步由一款专为 OceanBase 打造的开发者工具演进成为支持多数…

xCode14.3.1运行MonkeyDev出现“Executable Not Found“的解决办法

安装MonkeyDev遇到的坑 环境&#xff1a;Xcode Version 14.3.1 (14E300c) 错误提示 is not a valid path to an executable file. 报错 /Users/xxxx//Library/Developer/Xcode/DerivedData/MonTest-ccparhdyzjuqhjdergwrngpfwwoh/Build/Products/Debug-iphoneos/MonTest.app…

go-zerogo web集成redis实战

前言 上一篇&#xff1a;go-zero&go web集成JWT和cobra命令行工具实战 从零开始基于go-zero搭建go web项目实战-03集成redis实战 源码仓库地址 源码 https://gitee.com/li_zheng/treasure-box golang redis 客户端 Go-Redis 地址&#xff1a; GitHub: https://github.…

Maven 知识点总结

文章目录 Maven1、Maven 坐标2、Maven 仓库3、Maven 依赖依赖配置依赖范围依赖调解原则排除依赖 4、Maven 生命周期5、Maven 聚合与继承 Maven Maven是一个项目管理工具&#xff0c;它包含了项目对象模型&#xff08;POM&#xff1a;Project Object Model&#xff09;&#xf…

windows系统docker中将vue项目网站部署在nginx上

一、首先在windows系统上下载并安装docker&#xff0c;要下载windows版本 https://www.docker.com/products/docker-desktop/ PS&#xff1a;安装过程中需要WSL&#xff0c;我的是win11系统&#xff0c;直接提示了我安装就可以下一步了。其他windows系统版本我不知道是否需要单…

简化转换器:使用您理解的单词进行最先进的 NLP — 第 1 部分 — 输入

一、说明 变形金刚是一种深度学习架构&#xff0c;为人工智能的发展做出了杰出贡献。这是人工智能和整个技术领域的一个重要阶段&#xff0c;但也有点复杂。截至今天&#xff0c;变形金刚上有很多很好的资源&#xff0c;那么为什么要再制作一个呢&#xff1f;两个原因&#xff…