C++ 快速排序快速选择

目录

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]);elsecur++;}}
};

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]);elsei++;}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]);elsei++;}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;elsereturn 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]);elsei++;}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;elsereturn 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.hqwc.cn/news/504192.html

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

相关文章

D*算法超详解 (D星算法 / Dynamic A*算法/ Dstar算法)(死循环解决--跟其他资料不一样奥)

所需先验知识&#xff08;没有先验知识可能会有大碍&#xff0c;了解的话会对D*的理解有帮助&#xff09;&#xff1a;A*算法/ Dijkstra算法 何为D*算法 Dijkstra算法是无启发的寻找图中两节点的最短连接路径的算法&#xff0c;A*算法则是在Dijkstra算法的基础上加入了启发函数…

iOS消息转发流程

当向Objc对象发送消息时&#xff0c;如果找到对象对应的方法&#xff0c;就会进入消息转发流程&#xff0c;给开发者提供一些最后的机会处理消息无法发送问题&#xff0c;以免出现程序崩溃。 1. 回调对象的resolveInstanceMethod方法&#xff0c;在这个方法中&#xff0c;允许开…

网络安全学习笔记1

1.了解kali及安装 vmware安装&#xff0c;用户名密码均为kali 2.metasploit是什么 3.metasploit攻击windows系统 在kali中打来终端 数据msfconsole 进入metasploit的控制终端界面 msf的使用法则&#xff1a; 1.使用模块 2.配置模块必选项 3.运行模块 三步操作、实现对…

Java多线程导出Excel示例

在之前的Java多线程导入Excel示例中演示了如何通过多线程的方式导入Excel&#xff0c;下面我们再来看下怎么通过多线程的方式导出Excel 还是直接上代码 首先是Controller import com.sakura.base.service.ExcelService; import org.springframework.beans.factory.annotation.…

分布式压测之Locust和Jmeter的使用

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 受限于单台机器的配置问题&#xff0c;我们在单台机器上达不到一…

pip降级在pycharm中

PyCharm依赖于"–build-dir"参数安装第三方库&#xff0c;但该参数在最新的23.0版pip中已删除 解决办法就是降级pip&#xff0c;PyCharm中选择File&#xff0c;找到编译器&#xff0c;点击pip&#xff0c;勾选对应版本即可 或者在cmd中执行运行python -m pip install…

npm digital envelope routines::unsupported

问题描述&#xff1a;npm运行命令报错&#xff1a;digital envelope routines::unsupported 原因&#xff1a;node版本过高 解决方案&#xff1a;在运行命令之前加上 SET NODE_OPTIONS--openssl-legacy-provider && SET NODE_OPTIONS--openssl-legacy-provider &&a…

vue实现水印功能

目录 一、应用场景 二、实现原理 三、详细开发 1.水印的实现方式 2.防止用户通过控制台修改样式去除水印效果&#xff08;可跳过&#xff0c;有弊端&#xff09; 3.水印的使用 &#xff08;1&#xff09;单页面/全局使用 &#xff08;2&#xff09;全局使用个别页面去掉…

nest.js使用nest-winston日志一

nest-winston文档 nest-winston - npm 参考&#xff1a;nestjs中winston日志模块使用 - 浮的blog - SegmentFault 思否 安装 cnpm install --save nest-winston winstoncnpm install winston-daily-rotate-file 在main.ts中 import { NestFactory } from nestjs/core; im…

算法刷题day20:二分系列

目录 引言概念一、借教室二、分巧克力三、管道四、技能升级五、冶炼金属六、数的范围七、最佳牛围栏 引言 这几天一直在做二分的题&#xff0c;都是上了难度的题目&#xff0c;本来以为自己的二分水平已经非常熟悉了&#xff0c;没想到还是糊涂了一两天才重新想清楚&#xff0…

Linux 开发工具vim、gcc/g++、makefile

目录 Linux编辑器-vim 1. 基本概念 2. 基本操作 3. 正常模式命令集 4. 末行模式命令集 5. 其他操作 6. 简单vim配置 Linux编译器-gcc/g 1、基本概念 2、程序翻译的过程 3. gcc如何完成程序翻译 4、动静态库 Linux项目自动化构建工具-make/Makefile 1、背景 2、…

JAVA工程师面试专题-《消息队列》篇

​​​​​​​ 1、为什么使用消息队列&#xff1f; 解耦、异步、削峰 2、消息队列有什么优缺点 优点&#xff1a;解耦、异步、削峰 缺点&#xff1a;系统可用性降低、系统复杂度提高、一致性问题 3、如何进⾏消息队列选型&#xff1f; Kafka&#xff1a; ○ 优点&…