力扣第406题 根据身高重建队列 c++ 贪心思维

news2024/7/3 18:12:33

题目

406. 根据身高重建队列

中等

相关标签

贪心   树状数组   线段树   数组   排序

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

示例 1:

输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。

示例 2:

输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]

提示:

  • 1 <= people.length <= 2000
  • 0 <= hi <= 106
  • 0 <= ki < people.length
  • 题目数据确保队列可以被重建

思路和解题方法

  • 首先,定义了一个静态成员函数cmp作为排序函数。在该函数中,根据题目要求,我们首先比较两个人的身高(a[0]和b[0]),如果身高相同,则按照第二个元素(a[1]和b[1])即前面身高大于等于自己的人数进行升序排序。如果身高不同,则按照身高降序排序。
  • 接下来,在reconstructQueue函数中,对输入的people数组进行排序,排序的依据是调用了上述定义的cmp函数。这样,排序后的数组就满足了题目要求:身高高的人排在前面,身高相同的人按照前面身高大于等于自己的人数进行排序。
  • 然后,创建一个空的二维向量que,用于存储重建后的队列。
  • 接下来,遍历排序后的people数组。对于每个人,根据其应该插入的位置(即前面身高大于等于自己的人数),使用insert函数将其插入到que中的对应位置。由于在插入之前已经按照身高和前面身高大于等于自己的人数进行了排序,所以每次插入操作都不会破坏已经插入的人的相对顺序。
  • 最后,返回重建后的队列que
  • 这种贪心的思路是基于以下观察:对于每个人,他的前面身高大于等于自己的人数已经确定了,而在重建队列时,只需要根据这个人数将其插入到合适的位置即可。由于已经按照身高和前面身高大于等于自己的人数进行了排序,所以每次插入操作都不会破坏已经插入的人的相对顺序。因此,通过贪心地从身高最高的人开始,依次将每个人插入到合适的位置,就可以得到满足题目要求的重建队列。

复杂度

        时间复杂度:

                O(n^2)

        在代码中,首先进行了一次排序操作,时间复杂度为O(nlogn),其中n是people数组的长度。然后,通过遍历排序后的数组,对于每个人都进行了一次插入操作。插入操作的平均时间复杂度为O(n),因为每个人可能需要插入到队列的任意位置。所以总体的时间复杂度为O(n^2)。

        空间复杂度

                O(n)

对于空间复杂度,除了输入的people数组外,额外使用了一个二维向量que来存储重建后的队列。队列的长度与people数组的长度相同,所以空间复杂度为O(n)。

c++ 代码

class Solution { 
public: 

    // 定义一个静态函数 cmp,用于比较两个 vector<int> 对象
    static bool cmp(const vector<int>& a, const vector<int>& b) { 
        // 如果 a 和 b 的第一个元素相同,则按照第二个元素进行比较,如果 a 的第二个元素小于 b 的第二个元素,则返回 true,否则返回 false
        if (a[0] == b[0]) return a[1] < b[1]; 
        // 如果 a 和 b 的第一个元素不同,则按照第一个元素进行比较,如果 a 的第一个元素大于 b 的第一个元素,则返回 true,否则返回 false
        return a[0] > b[0]; 
    }

    // 定义一个函数 reconstructQueue,接收一个 vector<vector<int>> 类型的参数 people
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) { 
        // 对 people 数组进行排序,排序规则为 cmp 函数定义的方式
        sort (people.begin(), people.end(), cmp); 
        // 定义一个空的 vector<vector<int>> 对象 que
        vector<vector<int>> que; 
        // 遍历 people 数组
        for (int i = 0; i < people.size(); i++) { 
            // 获取 people 数组中每个元素的第二个元素,即他们在队列中的位置,并赋值给 position 变量
            int position = people[i][1]; 
            // 在 que 数组的指定位置插入 people 数组中的元素,实现重新构造队列
            que.insert(que.begin() + position, people[i]); 
        } 
        // 返回重新构造后的队列
        return que; 
    } 
}; 

对比

用list优化后的代码

其优化是底层的相关知识

        具体来说,当需要在vector<int> que中插入或删除元素时,需要将该元素后面的所有元素向后移动或向前移动,以确保vector中的元素始终连续存储。这个过程的时间复杂度为O(n),其中n是vector中元素的数量。

        而在使用list<vector<int>> que时,插入或删除元素只需要修改相邻节点的指针,不需要移动元素本身,因此时间复杂度为O(1)。

class Solution {
public:
    // 身高从大到小排(身高相同k小的站前面)
    static bool cmp(const vector<int> a, const vector<int> b) {
        if (a[0] == b[0]) return a[1] < b[1]; // 如果身高相同,则按照k值从小到大排序
        return a[0] > b[0]; // 否则按照身高从大到小排序
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort (people.begin(), people.end(), cmp); // 对people进行排序,使其满足题目要求的顺序
        list<vector<int>> que; // 创建一个链表,存储排序后的people
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1]; // 获取当前人员的插入位置
            std::list<vector<int>>::iterator it = que.begin(); // 创建一个迭代器,指向链表头部
            while (position--) { // 寻找当前人员的插入位置
                it++; // 迭代器向后移动
            }
            que.insert(it, people[i]); // 在迭代器指向的位置前插入当前人员
        }
        return vector<vector<int>>(que.begin(), que.end()); // 将链表转换为二维向量并返回
    }
};

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

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

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

相关文章

Qt在Android上设置连接到指定的WIFI

在Android上使用Qt设置连接到指定的Wi-Fi网络需要使用Java代码来完成,涉及到Android平台特定的API和权限。接下来下面将会演示如何在Qt中调用Java代码来实现这一功能。 【1】在Qt项目中创建一个名为"AndroidWifiConnector"的Java类。 (新建文件,选择JAVA类型,名字…

解决 viteprees 中 vp-doc 内置样式影响组件预

解决 viteprees 中 vp-doc 样式影响组件预览 问题 当使用"vitepress": "1.0.0-rc.22"作为组件库文档时&#xff0c;会自动引入vitepress的默认主题&#xff0c; 其中vp-doc中有大量的html标签样式 ... .vp-doc table {display: block;border-collapse: …

前端开发技术栈(工具篇):2023深入了解webpack的安装和使用以及核心概念和启动流程(详细) 63.3k stars

目录 Webpack简介 Entry Module Chunk Loader Plugin Output Webpack的启动流程 Webpack的优缺点 Webpack的使用 1. 安装Webpack 2. 创建Webpack配置文件 3. 编写代码 4. 运行Webpack 5. 在HTML中引入打包后的文件 6. 执行编译命令 Webpack其他功能介绍 1. 使…

map与set

目录 set的key搜索树模拟 set内置的find与count函数 ​编辑 set的lower_bound与upper_bound内置函数、 map的key-value搜索树模拟 通过不同的方式向map中插入键值对。 map的遍历 ​编辑 map的operator的 [ ] 用法 关于map与set用法的几个例题 例题1&#xff1a; 随机…

V3Det大规模词汇视觉检测数据集与LaRS海上全景障碍物检测数据集

V3Det与LaRS是ICCV2023上发表的数据集工作&#xff0c;规模都比较大&#xff0c;后续有可能会用到&#xff0c;因此记录下来。 V3Det: Vast Vocabulary Visual Detection Dataset Paper: https://arxiv.org/abs/2304.03752 URL: https://v3det.openxlab.org.cn/ 在现实世界中…

Bootstrap中CSS媒体查询分辨率 @media(min-width)例子

Bootstrap中CSS媒体查询分辨率 media&#xff08;min-width&#xff09;例子 css media min-width max-width 解释&#xff1a; min-width 表示最小即大于等于max-width 表示最大即小于等于 media screen and (min-width : 320px) {html {font-size : 10px !important;} } medi…

geoserve 发布 Styles 样式时,设置边框、填充以及填充透明度

文章目录 需求分析需求 设置 geoserve 发布的 Styles 样式中的边框、填充以及填充透明度 分析 具体详细使用可参考这篇文文章:在 GeoServer 上发布 Shapefile 文件作为 WMS 数据 <?xml version="1.0" encoding=

Git Gui使用技巧

资料 https://www.runoob.com/w3cnote/git-gui-window.html 操作过程 创建仓库→添加远程仓库→扫描目录→文件移动→提交→上传 注意填注释 文件忽略 创建文件.gitignore→编写内容 *.log #文件 config.ini #文件 temp/ #目录

App分发的策略和注意事项2

当今的数字化时代中&#xff0c;移动应用程序已经成为了人们生活中不可或缺的一部分。随着智能手机的普及和移动互联网的快速发展&#xff0c;应用程序的分发方式也变得越来越多样化。 App分发是指将移动应用程序通过特定的渠道传递给终端用户的过程。在应用程序开发完成后&am…

MySQL 多表查询 事务 索引

目录 多表查询简介内连接查询 join on外连接查询 left join、right join子连接查询标量子查询列子查询 (in、not in)行子查询表子查询 多表查询案例 事务事务介绍操作 start transaction、commit、rollback事务四大特性(面试题) 索引索引介绍索引原理索引语法 index 上次学习了…

一款适用于勒索病毒应急演练加解密工具

decryption-encryption 介绍 #encryption.exe为加密脚本 #decryption.exe为解密脚本 1、运行加密脚本&#xff0c;点击运行程序输入密码&#xff1a;TaSt12.2 输入需要加密的文件路径或文件夹路径&#xff0c;确定后即可对路径下面的所有格式文件进行加密&#xff1b; 2、…

安卓核心板_天玑700、天玑720、天玑900_5G模块规格参数

5G安卓核心板是采用新一代蜂窝移动通信技术的重要设备。它支持万物互联、生活云端化和智能交互的特性。5G技术使得各类智能硬件始终处于联网状态&#xff0c;而物联网则成为5G发展的主要动力。物联网通过传感器、无线网络和射频识别等技术&#xff0c;实现了物体之间的互联。而…

淘宝API接口获取商品信息,订单管理,库存管理,数据分析

在淘宝开放平台中&#xff0c;每个API接口都有相应的文档说明和授权机制&#xff0c;以确保数据的安全性和可靠性。开发者可以根据自己的需求选择相应的API接口&#xff0c;并根据文档说明进行调用和使用。 淘宝开放平台API接口是一套REST方式的开放应用程序编程接口&…

Java注解及自定义注解

注解/元数据&#xff08;Annotation&#xff09;&#xff0c;是对代码级别的说明&#xff1b;在JDK1.5及以后版本引入的一个特性&#xff0c;与类、接口、枚举是在同一个层次。可以声明在包、类、字段、方法、局部变量、方法参数等的前面&#xff0c;用来对这些元素进行说明、注…

三、虚拟机的迁移和删除

虚拟机的本质就是文件(放在文件夹的)。因此虚拟机的迁移很方便&#xff0c;可以把安装好的虚拟系统这个文件夹整体拷贝或者剪切到另外的位置使用。删除也很简单&#xff0c;使用vmware进行移除&#xff0c;再点菜单->从磁盘删除即可&#xff0c;或者手动删除虚拟系统对应的文…

【C++入门系列】——类和对象中篇

​作者主页 &#x1f4da;lovewold少个r博客主页 ⚠️本文重点&#xff1a;C构造函数、构析函数、运算符重载等详解 &#x1f604;前篇文章链接&#xff1a;【类和对象上】http://t.csdnimg.cn/bTQ0Y 目录 前言 类的默认成员函数 构造函数 默认构造 全缺省和无参默认构造 …

vue3+vite引入图片不能再用require,要使用new Url(完整方法步骤)

由于vite里面没有require(), 所以需要封装个工具 export const getAssetURL (image) > {// 参数一: 相对路径// 参数二: 当前路径的URLreturn new URL(../assets/img/${image}, import.meta.url).href }

【Proteus仿真】【Arduino单片机】直流电机和步进电机

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用蜂鸣器、按键、直流电机、步进电机、ULN2003、L293D等。 主要功能&#xff1a; 系统运行后&#xff0c;K3键启动运行&#xff0c;K1和K2键控制…

飞驰云联:让企业文件同步变得更简单

在如今这个高度信息化的时代&#xff0c;企业的文件同步需求日益增长&#xff0c;如何高效、安全地实现文件同步已成为企业亟待解决的问题。飞驰云联的文件同步系统作为一款全新的解决方案&#xff0c;能够满足各种企业对于文件同步的需求&#xff0c;提高工作效率&#xff0c;…

JXLS2同一个sheet多个表格循环覆盖下面表格数据问题

excel 模版&#xff1a; 输出结果 java 代码片段&#xff1a; private static void test01(String name) throws IOException {try (InputStream in new FileInputStream(new File(String.format(gen, name)));OutputStream out new FileOutputStream(new File(String.for…