【分治专题】详解快排类型4道题

本文讲解分治下的快排类型的4道题,在讲解题目的同时提供AC代码,点击题目即可打开对应链接 

目录

1、颜色分类

2、排序数组

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

4、库存管理 III


1、颜色分类

解法(快排思想--三指针法使数组分三块):

类比数组分两块的思想【双指针系列讲过移动零【双指针精选题目】详解8道题-CSDN博客】,这里是将数组分成三块,那么我们可以再添加一个指针,实现数组分三块
设数组大小为 n ,定义三个指针 left, cur, right :

  • left :用来标记 0 序列的末尾,因此初始化为 -1 ;
  • cur :用来扫描数组,初始化为 0 ;
  • right :用来标记 2 序列的起始位置,因此初始化为 n 。

在 cur 往后扫描的过程中,保证:

  • [0, left] 内的元素都是 0 ;
  • [left + 1, cur - 1] 内的元素都是 1 ;
  • [cur, right - 1] 内的元素是待定元素;
  • [right, n] 内的元素都是 2 。

算法流程:
a. 初始化 cur = 0,left = -1, right = numsSize ;
b. 当 cur < right 的时候(因为 right 表示 2 序列的左边界,因此当 cur 碰到 right 时,说明已经将所有数据扫描完毕了),一直进行下面循环:
根据 nums[cur] 的值,可以分为下面三种情况:

  • ①、 nums[cur] == 0 说明这个位置的元素需要在 left + 1 的位置上,故交换 left + 1 与 cur 位置的元素,并且让 left++ (指向 0 序列的右边界),cur++ (为什么可以 ++ 呢,是因为 left + 1 位置要么是 0 ,要么是1 ,【因为lef+1位置肯定是cur指针要扫描或即将扫描的位置,即这个位置我们可认为判断过了】交换完毕之后,这个位置的值已经符合我们的要求,因此 cur++ );
  • ②、nums[cur] == 1 说明这个位置应该在 left 和 cur 之间,此时无需交换,直接让 cur++ ,判断下一个元素即可;
  • ③、nums[cur] == 2 说明这个位置的元素应该在 right - 1 的位置,故交换right - 1 与 cur 位置的元素,并且让 right-- (指向 2 序列的左边界),cur 不变(因为交换过来的数是没有被判断过的,因此需要在下轮循环中判断)

当循环结束之后:
[0, left] 表示 0 序列;
[left + 1, right - 1] 表示 1 序列;
[right, numsSize - 1] 表示 2 序列。

举例分析:

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

2、排序数组

数组划分为两块的快排存在的问题

当待排序序列已经有序下或当待排序序列中存在大量重复元素,快速排序的划分操作可能会导致极度不平衡的划分,例如每次选择的基准值都是序列中的最小或最大值或者每次选择的基准值都是序列中的最小或最大重复元素,这样划分的效率很差,递归执行的次数也达到n-1,时间复杂度:O(N*N),但当数组中元素重复时我们可利用数组划分为三块的快排来优化

 数组分为三块的快排

优化:

 

class Solution {
public:vector<int> sortArray(vector<int>& nums){srand(time(NULL));//种下随机数种子qsort(nums, 0, nums.size() - 1);return nums;}//快排void qsort(vector<int>& nums, int l, int r){if (l >= r) return;//区间只有一个元素或不存在时为递归出口//数组分为三块int key = getKey(nums, l, r);//获取[l,r]中的一个随机数作为基准值//快排最核心部分:划分int i = l, left = l - 1, right = r + 1;while (i < right){if (nums[i] < key) swap(nums[++left], nums[i++]);else if (nums[i] == key) i++;else swap(nums[--right], nums[i]);}//继续递归左区间和右区间//[l, left],[left + 1, right - 1], [right, r]qsort(nums, l, left);qsort(nums, right, r);}int getKey(vector<int>& nums, int left, int right){int r = rand();//获得随机数return nums[r % (right - left + 1) + left];//获取[left,right]内的一个随机数}
};

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

 本题为典型的topk问题,我之前文章有讲过用堆解决这种问题

 解题思路:

在快排中,把数组「分成三块」: [l, left] [left + 1, right - 1][right, r]

我们可以通过计算每一个区间内元素的「个数」,进而推断出我们要找的元素是在「哪一个区间」里面,最后直接去「相应的区间」去寻找最终结果即可。

下面的a,b,c表示对应<key,==key,>key各区间中的元素个数

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];//qsort中的判断条件会保证区间一定存在,故l>r的情况可以不考虑,考虑也不会错//获取[l,r]范围内随机一个基准值int key = getRandom(nums, l, r);//快排核心:划分int i = l, left = l - 1, right = r + 1;while (i < right){if (nums[i] < key) swap(nums[++left], nums[i++]);else if (nums[i] == key) i++;else swap(nums[--right], nums[i]);}//递归:求出第k大元素int c = r - right + 1, b = right - left - 1; //b:right - 1 - (left + 1) + 1if (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];}
};


4、库存管理 III

 解法一、排序:O(N*logN)

解法二、堆:O(N*logK)

解法三、快速选择算法

a,b,c为各个区间内的元素个数

class Solution {
public:vector<int> inventoryManagement(vector<int>& nums, int k) {   //为方便书写nums[]代表stock[],k代表cnt//本题快速选择算法是把前k小的元素丢到最前面,并不是为了排序srand(time(NULL));qsort(nums, 0, nums.size() - 1, k);return {nums.begin(), nums.begin() + k};}//快排void qsort(vector<int>& nums, int l, int r, int k){if (l >= r) return;int key = getRandom(nums, l, r);int i = l, left = l - 1, right = r + 1;while (i < right){if (nums[i] < key) swap(nums[++left],nums[i++]);else if (nums[i] == key) i++;else swap(nums[--right], nums[i]);}//划分int a = left - l + 1, b = right - left - 1;if (a >= k) qsort(nums, l, left, k);//去<key的区间内找,这里写为>或>=均可else if (a + b >= k) return;//说明前k个元素已找到else qsort(nums, right, r, k - a - b);}int getRandom(vector<int>& nums, int left, int right){return nums[rand() % (right - left + 1) + left];}
};

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

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

相关文章

专业建设数字平台

专业建设数字平台&#xff0c;遵循以学生发展为中心、以产出为导向的OBE理念&#xff0c;大数据赋能人才培养全过程管理&#xff0c;支撑专业数字化建设与专业认证等专项工作&#xff0c;平台围绕学院与专业建设中人才培养方案制定的顶层设计工作及全流程、全场景业务&#xff…

ARM常用汇编指令

文章目录 前言一、处理器内部数据传输指令MOV&#xff1a; 将数据从一个寄存器复制到另一个寄存器。MRS&#xff1a; 将特殊寄存器(CPSR,SPSR)中的数据传给通用寄存器。MSR&#xff1a; 将通用寄存器中的数据传给特殊寄存器(CPSR,SPSR)。 二、存储器访问指令LDR:用于从内存中加…

力扣面试题 16.06. 最小差

Problem: 面试题 16.06. 最小差 文章目录 题目描述思路即解法复杂度Code 题目描述 思路即解法 注意本题目的数据范围!!! 1.对数组a与数组b进行排序;获取a与b的数组长度aLen,bLen&#xff0c;定义一个long类型的变量min&#xff1b; 2.分别让两个指针i&#xff0c;j指向数组的开…

56. 合并区间 - 力扣(LeetCode)

题目描述 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 题目示例 输入&#xff1a;intervals [[1,3…

LeNet跟LeNet5详解

1 LeNet结构 主要是为了手写数字识别 具体结构讲解&#xff1a;从图中例子可得 1 先传入一个灰度图像尺寸为1x28x28&#xff0c;通道数为1&#xff0c;尺寸为28x28的灰度图像 2 第一层5x5卷积&#xff0c;经过公式 输入图像尺寸-卷积核尺寸2padding/步长1&#xff0c;&#…

༺༽༾ཊ—设计-抽象-05-工厂-模式—ཏ༿༼༻

名称&#xff1a;抽象工厂 类型&#xff1a;创建型 目的&#xff1a;当有多个抽象角色时使用的一种工厂模式。 抽象工厂模式可以向客户端提供一个接口&#xff0c;使 客户端在不必指定产品的具体情况下&#xff0c;创建多个产品族中的产品对象。 优点&#xf…

Linux第38步_编译“正点原子移植好的uboot”

uboot的全称是Universal Boot Loader&#xff0c;uboot是一个遵循GPL协议的开源软件&#xff0c;uboot是一个裸机代码&#xff0c;可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB等高级功能。 uboot官方的uboot源码是给所有的半导体厂商准备的。ST公司会…

v38.恒星金字塔

1.循环嵌套 1.1矩阵&#xff08;i&#xff0c;j&#xff09; i行 j列 将矩阵与循环嵌套结合起来: 2.2.于是&#xff0c;金字塔就是

基于QC-LDPC编码的循环移位网络的FPGA实现

一、桶式移位寄存器(barrel shifter) 八位桶式移位寄存器的VHDL实现如下&#xff0c;由于每一层结构相似&#xff0c;于是采用生成语句for_generate实现&#xff0c;使用该代码实现的RTL级分析和理论的结构一致&#xff0c;仿真结果也符合预期。 entity barrel_shift isGENE…

从关键新闻和最新技术看AI行业发展(2024.1.15-1.28第十五期) |【WeThinkIn老实人报】

Rocky Ding 公众号&#xff1a;WeThinkIn 写在前面 【WeThinkIn老实人报】旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的优化建议&#xff0c;一起交流学习&…

GEE数据集——MOD13A1.006Terra星搭载的中分辨率成像光谱仪获取的L3级植被指数产品

数据名称&#xff1a; MOD13A1.006 Modis 16天 Terra 500m 数据来源&#xff1a; NASA 时空范围&#xff1a; 2000-2022年 空间范围&#xff1a; 全国 波段 名称波段单位最小值最大值比例因子波长描述NDVIB1NDVI-2000100000.0001Normalized Difference Vegetation…

for循环里i++和++i的区别

主要有以下三个区别&#xff1a; 1、i是先改变i的值即加1后再使用i的值&#xff1b;而i是先使用i的值在改变它的值即加。 2、for循环内部仅形式不同&#xff1a;当i循环和i循环在for循环内部&#xff0c;虽然形式上明显不同&#xff0c;但输出结果可以一样。 public static …

“群载波”全频强插无线应急广播在高速公路交通管控中的应用

一、“群载波”全频强插应急广播系统基本概念 群载波应急广播系统的技术是北京恒星科通科技发展有限公司技术总监刘军先生多年从事无线通信与应急通信产品的研发&#xff0c;突破传统无线电理论&#xff0c;开创性地提出了“群载波”通信理论&#xff0c;并亲自投入很大精力潜心…

docker 安装python3.8环境镜像并导入局域网

一、安装docker yum -y install docker docker version #显示 Docker 版本信息 可以看到已经下载下来了 拉取镜像python3镜像 二、安装docker 中python3环境 运行本地镜像&#xff0c;并进入镜像环境 docker run -itd python-38 /bin/bash docker run -itd pyth…

Steam游戏免费玩 gamebox 一起来玩幻兽帕鲁吧

steam大作免费畅玩 幻兽帕鲁也有资源 UI设计精美 还有补票链接&#xff0c;点击一下&#xff0c;就能跳转至Steam商店 可以自定义安装位置 下载链接 gamebox&#xff1a;https://rssm666.lanzn.com/b039g6dqj

如何用一根网线和51单片机做简单门禁[带破解器]

仓库:https://github.com/MartinxMax/Simple_Door 支持原创是您给我的最大动力… 原理 -基础设备代码程序- -Arduino爆破器程序 or 51爆破器程序- 任意选一个都可以用… —Arduino带TFT屏幕——— —51带LCD1602——— 基础设备的最大密码长度是0x7F&#xff0c;因为有一位…

游戏设计模式

单列模式 概念 单例模式是一种创建型设计模式&#xff0c;可以保证一个类只有一个实例&#xff0c;并提供一个访问该实例的全局节点。 优点 可以派生&#xff1a;在单例类的实例构造函数中可以设置以允许子类派生。受控访问&#xff1a;因为单例类封装他的唯一实例&#xf…

小土堆pytorch学习笔记004

目录 1、神经网络的基本骨架-nn.Module的使用 2、卷积操作实例 3、神经网络-卷积层 4、神经网络-最大池化的使用 &#xff08;1&#xff09;最大池化画图理解&#xff1a; &#xff08;2&#xff09;代码实现&#xff1a; 5、神经网络-非线性激活 &#xff08;1&#xf…

预训练语言模型transformer

预训练语言模型的学习方法有三类&#xff1a;自编码&#xff08;auto-encode, AE)、自回归&#xff08;auto regressive, AR&#xff09;&#xff0c;Encoder-Decoder结构。 决定PTM模型表现的真正原因主要有以下几点&#xff1a; 更高质量、更多数量的预训练数据增加模型容量…

NAS系统折腾记 – 申请域名和数字签名

群晖NAS硬件和DSM安装完毕&#xff0c;现在已经可以在家里局域网的环境下正常服务了。下一个问题自然是考虑出门在外的时候&#xff0c;怎样能通过外网远程访问NAS的服务了。为此&#xff0c;我需要给我的NAS服务器申请一个便于记忆的域名&#xff0c;然后配合DDNS服务实现域名…