【每日一题】花期内花的数目+【差分数组】+【二分枚举】

news2024/12/23 22:34:56

文章目录

  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:差分数组
    • 方法二:二分查找
  • 写在最后

Tag

【差分数组】【二分查找】【数组】【2023-09-28】


题目来源

2251. 花期内花的数目


题目解读

每朵花都有自己的花期,有些花的花期会有重叠,也就是说某些时刻会有多朵花同时开放,你需要找出在某些时刻花开的数量。


解题思路

解题的思路其实很明确,即确定某个时刻花开的数目即可。朴素的想法就是枚举的花,根据所有花的花期更新所有的时间点的花开数目。这种方法的最坏时间复杂度为 O(n^2) n n n 为数组 flowers 的长度,由于本题的数据规模达到 1 0 5 10^5 105,因此朴素方法一定超时。

方法一:差分数组

我们维护一个有序哈希表 cnts,表示某个时刻花开的数量(有序哈希表根据时间节点升序排序),我们枚举数组 flowers 中的每朵花 flower

  • 将花期的开始位置时刻(花开的时刻)的花开数量加一,即 ++cnts[flower[0]]
  • 将花期的开始位置时刻的下一时刻(花谢的下一个时刻)的花开数量减一,即 --cnts[flowers[1] + 1]

我们对 flowers 中的每朵花都进行以上操作来更新 cnts

为什么这样更新 cnts?因为这样,我们累加 cnts 的某个时刻的花开数量,即可得到某个时刻的所有花开数量。

我们以上更新的只是两种时刻的花开数量,即花开的时刻和花谢的下一个时刻,其他时刻的花开数量没有更新。因为我们只需要关注 “观赏者” 赏花的时刻,因此将 cnts 中没有覆盖到的观赏者赏花的时刻的花开数量进行更新。通过以下代码进行更新:

for (auto preson : presons) {
	cnts[x]; // cnts 中没有键 x,就 cnts[x] = 0;否则不进行任何操作
}

然后,我们更新 cnts

int t = 0;
	for(auto &cnt : cnts){
		cnt.second = (t += cnt.second);
 }

t 表示当前花开的数目,这里我们利用的是差分数组的性质累加得到某个时刻花开的数目。

最后,输出对应时刻的花开数目到答案数组 res 中,并返回。

图解 cnts 的更新

现在以 示例 1 为例,来对以上的思路进行示例分析。

(1)flowers = [[1,6],[3,7],[9,12],[4,13]], people = [2,3,7,11]

(2)遍历数组 flowers,更新得到的 cnts 如下图所示:

(3)将 cnts 中没有覆盖到的观赏者赏花的时刻的花开数量进行更新:

(4)最后累加更新 cnts

实现代码

class Solution {
public:
    vector<int> fullBloomFlowers(vector<vector<int>>& flowers, vector<int>& persons) {
        map<int, int> cnts;   // 统计每个时刻有几朵花开
        for(auto &it : flowers){
            ++cnts[it[0]];
            --cnts[it[1]+1];
        }
        for(auto x : persons){
            cnts[x];  // 没有 cnts[x] 就设置 cnts[x] = 0;否则不用管
        }

        int t = 0;
        for(auto &cnt : cnts){
            cnt.second = (t += cnt.second);
        }

        vector<int> ret;
        for(auto &x : persons){
            ret.push_back(cnts[x]);
        }
        return ret;
    }
};

复杂度分析

时间复杂度: O ( n l o g n + m l o g m ) O(nlogn+mlogm) O(nlogn+mlogm) n n n 为数组 flowers 的长度。cnts 是有序哈希表,每次插入的时间为 O ( l o g n ) O(logn) O(logn),一共插入 n 个元素,构建有序集合的时间为 O ( n l o g n ) O(nlogn) O(nlogn) m m m 为数组 presons 的长度,插入 m 个元素到有序哈希表中的时间复杂度为 O ( m l o g m ) O(mlogm) O(mlogm)

空间复杂度: O ( n + m ) O(n+m) O(n+m)

方法二:二分查找

设:第 i 个人到达的时间为 presons[i],在 presons[i] 时间点之前的花开数目为 x,在 presons[i] 时间点之前的花谢的数目为 y。则,presons[i] 时间点还处于开花状态的花数目为 x - y

x 即为 start <= presons[i] 的花朵数目,y 即为 end < presons[i] 的花朵数目。

根据以上的分析,我们可以单独统计起始时间 start 和 结束时间 end,利用二分查找快速查找结果:

  • 首先,将所有的 startend 进行升序排序;
  • 利用二分查找到 s t a r t i < = p e r s o n s [ i ] start_i <= persons[i] starti<=persons[i] 的花朵数目 x,利用二分查找到 e n d i < = p e r s o n s [ i ] end_i <= persons[i] endi<=persons[i] 的花朵数目 y,则第 i 个人可以看到的花朵数目为 x - y
  • 依次遍历并统计每个人的查询结果。

实现代码

class Solution {
public:
    vector<int> fullBloomFlowers(vector<vector<int>>& flowers, vector<int>& people) {
        vector<int> start, end;
        for (auto flower : flowers) {
            start.push_back(flower[0]);
            end.push_back(flower[1]);
        }

        sort(start.begin(), start.end());
        sort(end.begin(), end.end());

        int m = people.size();
        vector<int> res(m);

        for(int i = 0; i < n; ++i) {
            int x = upper_bound(start.begin(), start.end(), people[i]) - start.begin();
            int y = lower_bound(end.begin(), end.end(), people[i]) - end.begin();
            res[i] = x - y; 
        }
        return res;
    }
};

复杂度分析

时间复杂度: O ( ( n + m ) l o g n ) O((n+m)logn) O((n+m)logn) n n n 为数组 flowers 的长度, m m m 为数组 presons 的长度。对 startend 排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn);对每个人进行二分查找的时间为 O ( l o g n ) O(logn) O(logn),有 m 个人,因此二分查找总时间复杂度为 O ( m l o g n ) O(mlogn) O(mlogn);所以总的时间复杂度为 O ( ( n + m ) l o g n ) O((n+m)logn) O((n+m)logn)

空间复杂度: O ( n ) O(n) O(n),使用的额外空间为 startend 数组,这两个数组排序使用的额外空间为 O ( l o g n ) O(logn) O(logn),因此总的空间复杂度为 O ( n ) + O ( l o g n ) = O ( n ) O(n) + O(logn) = O(n) O(n)+O(logn)=O(n)


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

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

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

相关文章

Turf处理等压线

Turf是一个用于空间分析的JavaScript库。它包括传统的空间操作、用于创建GeoJSON数据的辅助函数以及数据分类和统计工具。Turf可以作为客户端插件添加到您的网站&#xff0c;也可以使用Node.js在服务器端运行Turf。 Turf是一个模块化的js类库&#xff0c;所有的模块都是在packa…

【GDB】用 python 扩展 gdb

用 python 扩展 GDB .gdbinit 文件中实现自定义命令 mv 代码如下 define mvif $argc 2delete $arg0# 注意新创建的断点编号和被删除断点的编号不同break $arg1elseprint "输入参数数目不对&#xff0c;help mv 以获得用法"end end# (gdb) help mv 会输出以下帮助文…

搭建自己的搜索引擎之四

一、前言 搭建自己的搜索引擎之三 介绍了通过HTTP RESTful 对ES进行增删改查&#xff0c;这一般手工运维ES时使用&#xff0c;程序代码中最好还是使用Java API去操作ES会更容易维护&#xff0c;但ES API竟然贼多&#xff0c;本篇介绍一下 四种 API及其简单使用。 注&#xff…

深入理解二叉树:结构、遍历和实现

文章目录 &#x1f34b;引言&#x1f34b;什么是二叉树&#xff1f;&#x1f34b;二叉树的基本性质&#x1f34b;二叉树的遍历&#x1f34b;二叉树的实现&#x1f34b;结语 &#x1f34b;引言 在计算机科学中&#xff0c;二叉树是一种重要的数据结构&#xff0c;广泛应用于各种…

【密评】商用密码应用安全性评估从业人员考核题库(二)

商用密码应用安全性评估从业人员考核题库&#xff08;二&#xff09; 国密局给的参考题库5000道只是基础题&#xff0c;后续更新完5000还会继续更其他高质量题库&#xff0c;持续学习&#xff0c;共同进步。 251 多项选择题 根据《密码法》&#xff0c;核心密码、普通密码安全…

Linux常用命令(一)

目录 一、列出目录内容&#xff08;ls&#xff09; 二、切换目录&#xff08;cd&#xff09; 三、显示当前目录路径&#xff08;pwd&#xff09; 四、以树状结构显示目录内容&#xff08;tree&#xff09; 五、创建新目录&#xff08;mkdir&#xff09; 六、复制文件或目…

windows11 如何关闭 vbs

在Windows 11中&#xff0c;VBS是一种虚拟化安全功能&#xff0c;它可以防止恶意软件通过沙箱环境运行。 如果您想关闭VBS功能&#xff0c;方法如下&#xff1a; 点击底部开始菜单 在上方搜索 cmd &#xff0c;并点击以管理员身份运行 打开控制台后&#xff0c;在控制台输入…

文档图像处理:大模型的突破与新探索

前言 随着数字化时代的到来&#xff0c;文档图像处理技术在各行各业扮演着越来越重要的角色。在2023第十二届中国智能产业高峰论坛&#xff08;CIIS 2023&#xff09;的专题论坛上&#xff0c;合合信息智能技术平台事业部副总经理、高级工程师丁凯博士分享了当前文档图像处理面…

wallis匀色算法、直方图匹配、颜色转移方法比较

算法原理 这三种方法应该是比较基础的匀色处理算法 三个算法的原理比较简单&#xff0c;具体原理大家可以自己百度 &#xff08;1&#xff09;wallis匀色原理主要在于利用Wallis滤波器使原始图像的均值和标准差与参考影像相当&#xff0c;从而使原始影像和参考影像具有相近的色…

Oracle的递归公共表表达式

查询节点id为2的所有子节点的数据&#xff0c;包括向下级联 WITH T1 (id, parent_id, data) AS (SELECT id, parent_id, dataFROM nodesWHERE id 2UNION ALLSELECT t.id, t.parent_id, t.dataFROM nodes tJOIN T1 n ON t.parent_id n.id ) SELECT * FROM T1; --建表语句 C…

今天出门竟然忘了带套

今天是没有抢到票的打工人节前的最后一天&#xff0c;7点醒来&#xff0c;磨磨蹭蹭&#xff0c;解决完个人问题&#xff0c;7.35才出门&#xff0c;正常来说最晚7.30出门&#xff0c;骑上哈啰、挤上地铁才能保证打上卡。 说出来不怕各位同行笑话&#xff0c;谁能想到一个高速发…

打卡新“姿势”,多种打卡方式并行

打卡工具 路径 拓展 >> 工具 功能简介 在打卡工具 “班次管理”中&#xff0c;支持多种打卡方式。可同时选择「地点打卡」和「智能安全帽打卡」两种方式进行打卡。 注&#xff1a; 「地点打卡」可设置考勤地点&#xff1b; 「智能安全帽打卡」可设置电子围栏范围。…

排序篇(一)----插入排序

1.直接插入排序 插入排序的思想: 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。 你可以想像成打牌一样,比如说斗地主,一张一张的摸牌,然后把手上的这些牌变成手续的排列.…

【教学类-38】A4红纸-国旗灯笼(庆祝中华人民共和国成立74周年)

作品展示&#xff1a; 背景需求&#xff1a; 从教十余年&#xff0c;我在每年国庆都带领中大班孩子们制作与“国旗相关”国庆庆祝物品——国旗、礼盒 一、国旗&#xff08;吸管、A4红纸、黄纸打印五角星&#xff09; 二、铅画纸手提袋&#xff08;8K铅画纸、A4红纸、黄色打印…

Windows的批处理——获取系统时间、生成当天日期日志

Windows批处理基础https://coffeemilk.blog.csdn.net/article/details/132118351 一、Windows批处理的日期时间 在我们进行软件开发的过程中&#xff0c;有时候会使用到一些批处理命令&#xff0c;其中就涉及到获取系统日期、时间来进行一些逻辑的判断处理&#xff1b;那么我们…

Ubuntu 部署 Seata1.7.1

一、环境说明 IP操作系统程序备注10.0.61.22ubuntu20.04PostgreSQL-14.11已提前部署10.0.61.21ubuntu20.04Nacos-2.1.0已提前部署10.0.61.22ubuntu20.04seata-server-1.7.1本文将要部署 二、部署 1. 下载 wget https://github.com/seata/seata/releases/download/v1.7.1/se…

VUE2项目:尚品汇VUE-CLI脚手架初始化项目以及路由组件分析(一)

标题 环境VUE2目录publicassetscomponentsmain.jsbabel.config.jspackage.jsonvue.config.js 项目路由分析Header与Footer非路由组件完成Header示例 路由组件的搭建声明式导航编程式导航 Footer组件的显示与隐藏路由传递参数重写push和replace三级联动组件拆分附件 环境 前提要…

Scala第四章节

Scala第四章节 scala总目录 章节目标 掌握分支结构的格式和用法掌握for循环和while循环的格式和用法掌握控制跳转语句的用法掌握循环案例理解do.while循环的格式和用法 1. 流程控制结构 1.1 概述 在实际开发中, 我们要编写成千上万行代码, 代码的顺序不同, 执行结果肯定也…

GD32工程创建

1.创建空工程 在任意路径下创建空的test文件夹。打开keil5空工程创建空工程 选择对应的芯片型号&#xff1a; 然后把空工程保存到test文件夹下。会自动生成如下文件。 2. 添加组 下载GD32F10X的固件库&#xff1a;在百度里搜索GD32进入官网。 下载下来对应的文件如下&#xff…

问题记录 springboot 事务方法中使用this调用其它方法

原因: 因为代理对象中调用了原始对象的toString()方法,所以两个不同的对象打印出的引用是相同的