C++ 快速排序快速选择OJ

news2024/9/29 15:28:39

目录

1、75. 颜色分类

2、912. 排序数组

3、 215. 数组中的第K个最大元素

4、LCR 159. 库存管理 III


1、75. 颜色分类

 思路:利用快速排序思路,使用三指针分块进行优化。

  • [0,left]——小于key
  • [left+1,right-1]——等于key
  • [right,nums.size()]——大于key
class Solution {
public:
    void sortColors(vector<int>& nums) {
        int n = nums.size();
        int left = -1, right = n, cur = 0;
        while (cur < right) {
            if (nums[cur] == 0)
                swap(nums[++left], nums[cur++]);
            else if (nums[cur] == 2)
                swap(nums[--right], nums[cur]);
            else
                cur++;
        }
    }
};

2、912. 排序数组

 

思路:快排+三指针优化+随机选择基准元素

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        srand(time(NULL));
        qsort(nums,0,nums.size()-1);
        return nums;
    }
    int getRandom(vector<int>& nums,int left,int right){
        int i=rand();
        return nums[i%(right-left+1)+left];
    }
    void qsort(vector<int>& nums,int begin,int end){
        if(begin >= end)
            return;
        int i=begin,left=begin-1,right=end+1;
        int key=getRandom(nums,begin,end);
        while(i<right){
            if(nums[i]<key)
                swap(nums[++left],nums[i++]);
            else if(nums[i]>key)
                swap(nums[--right],nums[i]);
            else
                i++;
        }
        qsort(nums,begin,left);
        qsort(nums,right,end);
    }
};

3、 215. 数组中的第K个最大元素

思路:快速选择(快排+三指针分块+随机选择基准元素+递归排序时进入对应区间)

  • 第k个最大元素也就是排序(升序)后的倒数第k个

     <key               =key                >key
|————|————————|—————|

l          left left+1        right-1 right             r

        a                    b                        c(区间元素个数)

c表示在当前key(基准值)右侧的元素数量(即比key大的元素数量),b表示等于key的元素数量。由于我们是寻找第k个最大的元素,数组的右侧代表了较大的元素。

  • if (c >= k):如果key右侧的元素数量c大于或等于k,这意味着第k个最大的元素位于key的右侧或者是key本身。因此,我们递归地在key右侧的数组部分继续进行快速选择,寻找第k个最大的元素。

  • else if (b + c >= k):如果key右侧的元素数量c加上等于key的元素数量b大于或等于k,这意味着第k个最大的元素要么是key本身,要么在等于key的这些元素中。由于这些元素都是相等的,我们可以直接返回key作为第k个最大的元素。

  • else:如果上述两个条件都不满足,这意味着第k个最大的元素位于key的左侧。因此,我们递归地在pivot左侧的数组部分继续进行快速选择。此时,我们需要调整k的值,因为我们已经排除了b + c个比key大或等于key的元素,所以新的k应该减去这部分已经排除的元素数量。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        srand(time(NULL));
        return qsort(nums, 0, nums.size() - 1, k);
    }
    int qsort(vector<int>& nums, int l, int r, int k) {
        if (l == r)
            return nums[l];
        int key = getRandom(nums, l, r);
        int left = l - 1, right = r + 1, i = l;
        while (i < right) {
            if (nums[i] < key)
                swap(nums[++left], nums[i++]);
            else if (nums[i] > key)
                swap(nums[--right], nums[i]);
            else
                i++;
        }
        int c = r - right + 1, b = right - left - 1;
        if (c >= k)
            return qsort(nums, right, r, k);
        else if (b + c >= k)
            return key;
        else
            return qsort(nums, l, left, k - b - c);
    }
    int getRandom(vector<int>& nums, int left, int right) {
        return nums[rand() % (right - left + 1) + left];
    }
};

 为了找到数组中第k个最大的元素,并且要求时间复杂度为O(n),我们可以比较这些方法:

  1. 快速选择算法(第一种方法):

    • 优点: 平均时间复杂度为O(n),符合题目要求。它通过随机选择一个枢轴来分割数组,然后只在包含第k个最大元素的那部分数组上递归,从而减少了不必要的计算。
    • 缺点: 最坏情况下的时间复杂度为O(n^2),但这种情况很少发生。算法的性能依赖于随机数的选择。
  2. 最小堆(第二种方法):

    • 优点: 对于找到第k个最大元素,这种方法维护了一个大小为k的最小堆,时间复杂度为O(n log k),适合k远小于n的情况。
    • 缺点: 当k接近n时,性能不如快速选择算法。
      class Solution {
      public:
          int findKthLargest(vector<int>& nums, int k) {
              priority_queue<int,vector<int>,greater<int>> pq(nums.begin(),nums.begin()+k);
              for(size_t i=k;i<nums.size();i++){
                  if(nums[i]>pq.top()){
                      pq.pop();
                      pq.push(nums[i]);
                  }
              }
              return pq.top();
          }
      };

  3. 排序(第三种方法):

    • 优点: 实现简单,直观易懂。
    • 缺点: 时间复杂度为O(n log n),不满足题目对O(n)时间复杂度的要求。
      class Solution {
      public:
          int findKthLargest(vector<int>& nums, int k) {
              sort(nums.begin(),nums.end());
              return nums[nums.size()-k];
          }
      };
  4. 最大堆(第四种方法):

    • 优点: 通过构建一个最大堆,然后弹出k-1次,可以直接得到第k个最大元素。这种方法简单且对于理解堆结构很有帮助。
    • 缺点: 时间复杂度为O(n + k log n),当k较小相对高效,但当k接近n时,性能下降。
      class Solution {
      public:
          int findKthLargest(vector<int>& nums, int k) {
              priority_queue<int> pq(nums.begin(),nums.end());
              while(--k){
                  pq.pop();
              }
              return pq.top();
          }
      };

结论:

  • 如果你追求平均情况下的最优时间复杂度,并且可以接受在极少数情况下性能的不确定性,快速选择算法是最佳选择。
  • 如果k值较小,最小堆方法也是一个不错的选择,因为它可以较快地找到第k个最大的元素。
  • 排序方法虽然简单,但不满足题目对时间复杂度的要求。
  • 最大堆方法适用于k值较小的情况,但当k值较大时,性能不是最优的。

综上所述,考虑到时间复杂度的要求和算法的效率,快速选择算法是最符合题目要求的解决方案

4、LCR 159. 库存管理 III

思路:快速选择(快排+三指针分块+随机选择基准元素+进入对应区间寻找)
     <key               =key                >key
|————|————————|—————|

l          left left+1        right-1 right             r

        a                    b                        c(区间元素个数)

a表示在当前的key(基准值)左边的元素数量,b表示等于key的元素数量。cnt是我们需要找到的库存余量最少的商品数量。

  • if (a > cnt):如果key左边的元素数量a大于cnt,这意味着我们需要的cnt个最小元素全部位于key的左边。因此,我们递归地在key左边的数组部分继续进行快速选择,寻找这cnt个最小元素。

  • else if (a + b >= cnt):如果key左边的元素数量a加上等于key的元素数量b大于或等于cnt,这意味着我们需要的cnt个最小元素已经包含在左边的元素和等于key的元素中。由于题目说明返回顺序不限,我们不需要进一步排序或选择,可以直接返回结果。

  • else:如果上述两个条件都不满足,这意味着我们需要的cnt个最小元素部分位于key的右边。因此,我们递归地在key右边的数组部分继续进行快速选择。此时,我们需要调整cnt的值,因为我们已经找到了一部分所需的最小元素(即a + b个),所以新的cnt应该减去这部分已经找到的元素数量。

class Solution {
public:
    vector<int> inventoryManagement(vector<int>& stock, int cnt) {
        srand(time(NULL));
        qsort(stock, 0, stock.size() - 1, cnt);
        return {stock.begin(), stock.begin() + cnt};
    }
    int qsort(vector<int>& stock, int l, int r, int cnt) {
        if (l == r)
            return stock[l];
        int key = getRandom(stock, l, r);
        int left = l - 1, right = r + 1, i = l;
        while (i < right) {
            if (stock[i] < key)
                swap(stock[++left], stock[i++]);
            else if (stock[i] > key)
                swap(stock[--right], stock[i]);
            else
                i++;
        }
        int a = left - l + 1, b = right - left - 1;
        if (a > cnt)
            return qsort(stock, l, left, cnt);
        else if (a + b >= cnt)
            return 0;
        else
            return qsort(stock, right, r, cnt - b - a);
    }
    int getRandom(vector<int>& stock, int left, int right) {
        return stock[rand() % (right - left + 1) + left];
    }
};

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

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

相关文章

Day 6.有名信号量(信号灯)、网络的相关概念和发端

有名信号量 1.创建&#xff1a; semget int semget(key_t key, int nsems, int semflg); 功能&#xff1a;创建一组信号量 参数&#xff1a;key&#xff1a;IPC对像的名字 nsems&#xff1a;信号量的数量 semflg&#xff1a;IPC_CREAT 返回值&#xff1a;成功返回信号量ID…

惠普 DsekJet GT 5810/5820常见问题及解决方法

1、HP DeskJet GT 5810/5820机器的屏幕出现“P”时&#xff0c;该如何操作&#xff1f; 当屏幕出现“P”时&#xff0c;放入A4纸&#xff0c;按住“进纸键”3秒即可&#xff0c;打印机会打印出一张校准页。 2、HP DeskJet GT 5810/5820机器的屏幕出现“A”时&#xff0c;该如何…

反射(重点)

1.反射的概述 Java给我们提供了一套API&#xff0c;使用这套API我们可以在运行时动态的获取指定对象所属的类&#xff0c;创建 运行时类的对象&#xff0c;调用指定的结构&#xff0c;(属性&#xff0c;方法)等 API&#xff1a; java.lang.Class&#xff1a;代表一个类 jav…

JSP实现数据传递与保存

1.HTML页面转换JSP页面 直接再HTML页面最顶端添加page指令&#xff0c;修改文件后缀名&#xff1b;反之&#xff1b; 2.JSP内置对象 对象 描述 request 每当客户端请求JSP页面时&#xff0c;JSP引擎会制造一个新的request对象来代表这个请求。 response 当服务器创建req…

keycloak-鉴权springboot

一、环境描述 keycloak鉴权springboot的方式&#xff0c;此处简单介绍&#xff0c;springboot官方也提供了demo https://github.com/keycloak/keycloak-quickstarts/tree/latest/spring/rest-authz-resource-server 以及文档说明 Securing Applications and Services Guide…

ruoyi-nbcio-plus的Vue3前端一些插件使用介绍(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a; http://122.227.135.243:9666 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbach…

微信小程序自动化测试——微信小程序云测服务!

MiniTest 微信小程序云测服务是一套由微信测试团队自主研发&#xff0c;联合WeTest云真机能力&#xff0c;共同推出的微信小程序自动化测试服务。 服务基于云真机&#xff0c;支持开发者简单快捷地实现小程序智能化Monkey测试&#xff0c;录制回放&#xff0c;自定义测试和性能…

基于springboot+vue的医疗报销系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

YOLO算法改进Backbone系列之:RepViT

摘要&#xff1a;近年来&#xff0c;与轻量级卷积神经网络(cnn)相比&#xff0c;轻量级视觉变压器(ViTs)在资源受限的移动设备上表现出了更高的性能和更低的延迟。这种改进通常归功于多头自注意模块&#xff0c;它使模型能够学习全局表示。然而&#xff0c;轻量级vit和轻量级cn…

猫咪冻干的价格差别为什么那么大?价格实惠的主食冻干分享

随着养猫科学知识的普及&#xff0c;越来越多的铲屎官选择更符合猫咪饮食天性的主食冻干喂养。尽管有些铲屎官因价格犹豫&#xff0c;但像我这样的资深铲屎官深知其益处。尽管其价格稍高于烘焙粮和膨化粮&#xff0c;但主食冻干为猫咪健康带来的实际好处是无法估量的。 对于像我…

约课小程序有哪些功能

​约课小程序为教育机构、教师和学生提供了便捷的预约和管理服务&#xff0c;有效提升了教学效率和用户体验。在这篇文章中&#xff0c;我们将介绍约课小程序常见的功能&#xff0c;帮助教育机构更好地了解如何利用小程序来提升服务质量和管理效率。 1. **课程预约功能**&…

基于openKylin与RISC-V的MindSpore AI项目实践

项目目标&#xff1a; 在openKylin系统上安装和配置MindSpore框架。开发一个简单的图像分类模型&#xff0c;并在RISC-V平台上进行训练和推理。根据RISC-V的特性&#xff0c;对MindSpore框架进行必要的优化。 目录 项目目标&#xff1a; 训练模型 编写训练代码&#xff0c;设…

美易官方《盘前:美国股指期货温和走低》

美国股指期货在盘前交易中温和走低&#xff0c;市场情绪在美联储主席鲍威尔即将作证前显得谨慎。投资者对即将公布的证词内容充满期待&#xff0c;以寻求对美联储未来货币政策的更多线索。 鲍威尔即将在国会作证&#xff0c;这是市场关注的焦点事件之一。他的证词可能会对美元汇…

用有名管道实现进程AB之间的对话

题目 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <unistd.h> int main(int argc, const char *argv[]) {//创建一个有名管道文件if(mk…

【力扣白嫖日记】1045.买下所有产品的客户

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1045.买下所有产品的客户 表&#xff1a;Customer 列名类型customer_idintproduct_keyint 该表可能包含重复…

市场复盘总结 20240305

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 25% 最常用的…

【打工日常】使用docker部署轻量的运维监控工具

一、Uptime-Kuma介绍 Uptime-Kuma是一个轻量级的自动化运维监控工具&#xff0c;最为引人注目的特点是其出色的监控Dashboard面板。部署简单&#xff0c;工具轻量又强大。而且&#xff0c;Uptime-Kuma是开源免费的&#xff0c;并支持基于Docker的部署方式。它支持网站、容器、数…

动静态库-动态库加载

动静态库 前言引入 一、静态库1. 创建静态库①原理②创建 2. 使用静态库①借助编译选项②只需要带库名 3. 小结 二、动态库1. 创建动态库2. 使用动态库 三、 动态库加载原理——进程地址空间1. 地址①程序没有被加载前的地址②程序加载后的地址 2. 原理①动态库的地址②原理 前…

实用干货:分享一个自动切换输入法的IDE插件

大家好&#xff0c;我是大澈&#xff01; 本文约1100字&#xff0c;整篇阅读大约需要3分钟。 关注微信公众号&#xff1a;“程序员大澈”&#xff0c;免费加入问答群&#xff0c;一起交流技术难题与未来&#xff01; 现在关注公众号&#xff0c;免费送你 ”前后端入行大礼包…

C++入门全集(5):内存管理

前言 一、内存区域划分 二、C的内存管理方式 2.1 对内置类型 2.2 对自定义类型 三、new和delete的底层实现 四、new和delete的原理 五、定位new 六、malloc/free和new/delete 前言 在C中&#xff0c;内存管理是不可避免的一门必修课。C对内存的自由度使其获得了更高的…