优选算法之 分治-快排

目录

一、颜色分类

1. 题目链接:75. 颜色分类

2. 题目描述:

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

🌴算法思路:

🌴算法流程:

🌴算法代码:

二、快速排序

1. 题目链接:912. 排序数组

2. 题目描述:

3. 解法(数组分三块思想 + 随机选择基准元素的快速排序):

🌴算法思路:

🌴算法流程:

🌴算法代码:

三、快速选择算法

1. 题目链接:215. 数组中的第K个最大元素

2. 题目描述:

3. 解法

🌴算法思路:

🌴算法代码:

四、最小的K个数

1. 题目链接:LCR 159. 库存管理 III

2. 题目描述:

3. 解法

🌴算法思路:

🌴算法代码:


一、颜色分类

1. 题目链接:75. 颜色分类

2. 题目描述:

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 01 或 2

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

🌴算法思路:

        类比数组分两块的算法思想,这里是将数组分成三块,那么我们可以再添加⼀个指针,实现数组分三块。

设数组大小为 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] 的值,可以分为下面三种情况:

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

c. 当循环结束之后:

  • [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, right = n, i = 0;while (i < right){if(nums[i] == 0) swap(nums[++left], nums[i++]);else if(nums[i] == 1) i++;else swap(nums[--right], nums[i]);}}
};

二、快速排序

1. 题目链接:912. 排序数组

2. 题目描述:

给你一个整数数组 nums,请你将该数组升序排列。

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

提示:

  • 1 <= nums.length <= 5 * 104
  • -5 * 104 <= nums[i] <= 5 * 104

3. 解法(数组分三块思想 + 随机选择基准元素的快速排序):

🌴算法思路:

        由快速排序的思想可以知道,快排最核心的⼀步就是 Partition (分割数据):将数据按照一个标准,分成左右两部分。

        如果我们使用荷兰国旗问题的思想,将数组划分为 左 中 右 三部分:左边是比基准元素小的数据,中间是与基准元素相同的数据,右边是比基准元素大的数据。然后再去递归的排序左边部分和右边部分即可(可以舍去大量的中间部分)。

        在处理数据量有很多重复的情况下,效率会大大提升。

🌴算法流程:

随机选择基准算法流程:

函数设计:int randomKey(vector<int>& nums, int left, int right)

  1. 在主函数那里种⼀颗随机数种子;
  2. 在随机选择基准函数这里生成⼀个随机数;
  3. 由于我们要随机产生⼀个基准,因此可以将随机数转换成随机下标:让随机数 % 上区间大小,然后加上区间的左边界即可。

快速排序算法主要流程:

a. 定义递归出口;;

b. 利用随机选择基准函数生成⼀个基准元素;

c. 利用荷兰国旗思想将数组划分成三个区域;

d. 递归处理左边区域和右边区域。

🌴算法代码:

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 = 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]);}// [l, left] [left+1, right-1] [right, r]qsort(nums, l, left);qsort(nums, right, r);}int getRandom(vector<int>& nums, int left, int right){int r = rand();return nums[r % (right - left + 1) + left];}
};

三、快速选择算法

1. 题目链接:215. 数组中的第K个最大元素

2. 题目描述:

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

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

示例 2:

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

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

3. 解法

🌴算法思路:

        在快排中,当我们把数组「分成三块」之后: [l, left] [left + 1, right - 1][right, r] ,我们可以通过计算每一个区间内元素的「个数」,进而推断出我们要找的元素是在「哪一个区间」里面。那么我们就可以直接去「相应的区间」寻找最终结果啦。

🌴算法代码:

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];// 1.随机选择基准元素int key = getRandom(nums, l, r);// 2.根据基准元素将数组分三块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]);}// 3.分情况讨论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个数

1. 题目链接:LCR 159. 库存管理 III

2. 题目描述:

仓库管理员以数组 stock 形式记录商品库存表,其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量,返回 顺序不限

示例 1:

输入:stock = [2,5,7,4], cnt = 1
输出:[2]

示例 2:

输入:stock = [0,2,3,6], cnt = 2
输出:[0,2] 或 [2,0]

提示:

  • 0 <= cnt <= stock.length <= 10000
    0 <= stock[i] <= 10000

3. 解法

🌴算法思路:

        在快排中,当我们把数组「分成三块」之后: [l, left] [left + 1, right - 1][right, r] ,我们可以通过计算每⼀个区间内元素的「个数」,进而推断出最小的 k 个数在哪些区间里面。那么我们可以直接去「相应的区间」继续划分数组即可。

🌴算法代码:

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};}void qsort(vector<int>& stock, int l, int r, int cnt){if(l >= r) return;//选择基准元素 + 数组分三块int key = keyRandom(stock, l, r);int i = l, left = l - 1, right = r + 1;while(i < right){if(stock[i] < key) swap(stock[++left], stock[i++]);else if(stock[i] == key) i++;else swap(stock[--right], stock[i]);}// 分情况讨论// [l, left] [left + 1, right - 1] [right, r]int a = left - l + 1, b = right - left - 1;if(a > cnt) return qsort(stock, l, left, cnt);else if(a + b >= cnt) return;else return qsort(stock, right, r, cnt - a - b);}int keyRandom(vector<int>& stock, int l, int r){return stock[rand() % (r - l + 1) + l];}
};

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

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

相关文章

【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(上)

系列文章目录 【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器&#xff08;上&#xff09; 【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器&#xff08;下&#xff09; 文章目录 系列文章目录前言一、ArkTS基本介绍1、 ArkTS组成2、组件参数和属性2.1、区…

YOLOV8 OpenCV + usb 相机 实时识别

1 OpenCV 读相机 import cv2cap cv2.VideoCapture(0) while (1):# get a frameret, frame cap.read()# show a framecv2.imshow("capture", frame)if cv2.waitKey(1) & 0xFF ord(q):# cv2.imwrite("/opt/code/image/fangjian2.jpeg", frame)#passb…

Linux基础知识-1

Linux和Windows最大差异:目录。在Windows中&#xff0c;磁盘是被分成了很多区的&#xff0c;比如C盘&#xff0c;D盘&#xff0c;不同的文件放在不同的盘下面。下图为Windows的磁盘管理&#xff0c;可以看到磁盘0被划分为了不同的区域&#xff0c;C盘&#xff0c;D盘等&#xf…

[深度学习]Pytorch框架

1 深度学习简介 应用领域:语音交互、文本处理、计算机视觉、深度学习、人机交互、知识图谱、分析处理、问题求解2 发展历史 1956年人工智能元年2016年国内开始关注深度学习2017年出现Transformer框架2018年Bert和GPT出现2022年,chatGPT出现,进入AIGC发展阶段3 PyTorch框架简…

2024 年 CSS 终于增加了垂直居中特性,效率翻倍!

在 2024 年的Chrome 123 版本中&#xff0c; CSS 原生可以使用 1 个 CSS 属性 align-content: center进行垂直居中。 有何魅力&#xff1f; 这个特性的魅力在哪儿呢&#xff1f;我举例给你看一下 <div style"align-content:center; height:200px; background: #614e…

计算机网络:物理层 --- 基本概念、编码与调制

目录 一. 物理层的基本概念 二. 数据通信系统的模型 三. 编码 3.1 基本概念 3.2 不归零制编码 3.3 归零制编码 3.4 曼切斯特编码 3.5 差分曼切斯特编码 ​编辑 四. 调制 4.1 调幅 4.2 调频 4.3 调相 4.4 混合调制 今天我们讲的是物理…

影刀RPA实战:网页爬虫之携程酒店数据

1.实战目标 大家对于携程并不陌生&#xff0c;我们出行定机票&#xff0c;住酒店&#xff0c;去旅游胜地游玩&#xff0c;都离不开这样一个综合性的网站为我们提供信息&#xff0c;同时&#xff0c;如果你也是做旅游的公司&#xff0c;那携程就是一个业界竞争对手&#xff0c;…

[Spring]Spring MVC 请求和响应及用到的注解

文章目录 一. Maven二. SpringBoot三. Spring MVC四. MVC注解1. RequestMapping2. RequestParam3. PathVariable4. RequestPart5. CookieValue6. SessionAttribute7. RequestHeader8. RestController9. ResponseBody 五. 请求六. 响应 一. Maven Maven是⼀个项⽬管理⼯具。基于…

Python | Leetcode Python题解之第421题数组中两个数的最大异或值

题目&#xff1a; 题解&#xff1a; class Trie:def __init__(self):# 左子树指向表示 0 的子节点self.left None# 右子树指向表示 1 的子节点self.right Noneclass Solution:def findMaximumXOR(self, nums: List[int]) -> int:# 字典树的根节点root Trie()# 最高位的二…

Java基础知识扫盲

目录 Arrays.sort的底层实现 BigDecimal(double)和BigDecimal(String)有什么区别 Char可以存储一个汉字吗 Java中的Timer定时调度任务是咋实现的 Java中的序列化机制是咋实现的 Java中的注解是干嘛的 Arrays.sort的底层实现 Arrays.sort是Java中提供的对数组进行排序的…

LabVIEW编程能力如何能突飞猛进

要想让LabVIEW编程能力实现突飞猛进&#xff0c;需要采取系统化的学习方法&#xff0c;并结合实际项目进行不断的实践。以下是一些提高LabVIEW编程能力的关键策略&#xff1a; 1. 扎实掌握基础 LabVIEW的编程本质与其他编程语言不同&#xff0c;它是基于图形化的编程方式&…

使用 UWA Gears 定位游戏内存问题

UWA Gears 是UWA最新发布的无SDK性能分析工具。针对移动平台&#xff0c;提供了实时监测和截帧分析功能&#xff0c;帮助您精准定位性能热点&#xff0c;提升应用的整体表现。 内存不足、内存泄漏和过度使用等问题&#xff0c;常常导致游戏出现卡顿、崩溃&#xff0c;甚至影响…

CSS | 如何来避免 FOUC(无样式内容闪烁)现象的发生?

一、什么是 FOUC(无样式内容闪烁)? ‌FOUC&#xff08;Flash of Unstyled Content&#xff09;是指网页在加载过程中&#xff0c;由于CSS样式加载延迟或加载顺序不当&#xff0c;导致页面出现闪烁或呈现出未样式化的内容的现象。‌ 这种现象通常发生在HTML文档已经加载&…

Redis数据结构之哈希表

这里的哈希表说的是value的类型是哈希表 一.相关命令 1.hset key field value 一次可以设置多个 返回值是设置成功的个数 注意&#xff0c;哈希表中的键值对&#xff0c;键是唯一的而值可以重复 所以有下面的结果&#xff1a; key中原来已经有了f1&#xff0c;所以再使用hse…

RTSP学习

RTSP基本原理 实时流传输协议(RTSP:RealTimeStreaming Protocol1)是一种网络传输协议,旨在发送低延迟流。 该协议由RealNetworks,Netscape和哥伦比亚大学的专家在1996年开发。它定义了应如何打包流中的数据以进行传输。 类似一个控制命令的协议play teardown 负责音视频的数据…

二叉树(Java)

一.1.树形结构概念的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#xff1a;…

大模型培训讲师叶梓:Llama Factory 微调模型实战分享提纲

LLaMA-Factory ——一个高效、易用的大模型训练与微调平台。它支持多种预训练模型&#xff0c;并且提供了丰富的训练算法&#xff0c;包括增量预训练、多模态指令监督微调、奖励模型训练等。 LLaMA-Factory的优势在于其简单易用的界面和强大的功能。用户可以在不编写任何代码的…

【速成Redis】03 Redis 五大高级数据结构介绍及其常用命令 | 消息队列、地理空间、HyperLogLog、BitMap、BitField

前言&#xff1a; 上篇博客我们讲到redis五大基本数据类型&#xff08;也是就下图的第一列&#xff09;。 【速成Redis】02 Redis 五大基本数据类型常用命令-CSDN博客文章浏览阅读1k次&#xff0c;点赞24次&#xff0c;收藏10次。该篇适用于速成redis。本篇我们将讲解&#…

Leetcode 2246. 相邻字符不同的最长路径(一般树)树形dp C++实现

问题&#xff1a;Leetcode 2246. 相邻字符不同的最长路径 给你一棵 树&#xff08;即一个连通、无向、无环图&#xff09;&#xff0c;根节点是节点 0 &#xff0c;这棵树由编号从 0 到 n - 1 的 n 个节点组成。用下标从 0 开始、长度为 n 的数组 parent 来表示这棵树&#x…