分治精炼宝库-----快速排序运用(⌯꒪꒫꒪)੭

目录

一.基本概念:

一.颜色分类:

二.排序数组:

三.数组中的第k个最大元素:

解法一:快速选择算法

解法二:简单粗暴优先级队列

 四.库存管理Ⅲ:

解法一:快速选择

解法二:简单粗暴排序

解法三:简单粗暴优先级队列


一.基本概念:

🐻在计算机科学中,分治法是一种很重要的算法。字面上的解释就是“分而治之”,就是把一个复杂的问题分成两个或则更多个相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)……

 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算。n=2时,只要作一次比较即可排好序。n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。🧐分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

当我们对分治算法有了以上的一定了解后,来练习几道题目加深理解~~

注(本文承接上文:分治精炼宝库----归并排序应用( ´◔︎ ‸◔︎`)_用分治法归并排序-CSDN博客)

一.颜色分类:

说明:这里我们用到的快速排序会使用数组分三块的思想(下文会详细说明),从数组中随机取一个元素key,将数组划分为三个区域,区域① < key ,区域 ② = key ,区域③ > key

题目链接:75. 颜色分类 - 力扣(LeetCode)

算法思路:

  1. 使用左指针left和右指针right来划分数组,初始时left为-1,right为数组长度n。
  2. 遍历数组nums,使用变量i作为当前遍历的索引。
  3. 如果nums[i]等于0,则将nums[i]与left+1位置的值交换,并将left和i都加1。
  4. 如果nums[i]等于1,则继续遍历下一个值。
  5. 如果nums[i]等于2,则将nums[i]与right-1位置的值交换,并将right和i都减1。
  6. 重复步骤4-6,直到遍历完成整个数组。

核心步骤:

代码详解:

class Solution {public void sortColors(int[] nums) {//将数组划分为三个区域[0,1,2]int n = nums.length;for(int i = 0,left = -1,right = n;i < right;){if(nums[i] == 0){swap(nums,++left,i++);}else if(nums[i] == 1){i++;}else{swap(nums,--right,i);}}}public void swap(int[] nums,int i,int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}
}

运行结果:

二.排序数组:

题目链接:912. 排序数组 - 力扣(LeetCode)

这里我们使用快速排序来解决,首先,我们来一起看一下快速排序的核心框架:

void sort(int[] nums, int lo, int hi) {if (lo >= hi) {return;}// 对 nums[lo..hi] 进行切分// 使得 nums[lo..p-1] <= nums[p] < nums[p+1..hi]int p = partition(nums, lo, hi);// 去左右子数组进行切分sort(nums, lo, p - 1);sort(nums, p + 1, hi);
}

快速排序的核心即是先将一个元素排好序,再将剩下的元素排好序

 快速排序的核心无疑是 partition 函数, partition 函数的作用是在 nums[lo..hi] 中寻找一个切分点 p,通过交换元素使得 nums[lo..p-1] 都小于等于 nums[p],且 nums[p+1..hi] 都大于 nums[p].

一个元素左边它小,右边都比它大,什么意思?不就是把它放到正确的排好序的位置上了吗?

所以 partition 函数干的事情,其实就是把 nums[p] 这个元素排好序了。

一个元素被排好序了,然后呢?你再把剩下的元素排好序不就行了嘛,排序图解:

其实我们不难发现,拍好序的数组就是一颗二叉搜索树!快速排序的过程其实也就是构造一棵二叉搜索树的过程

 但谈到二叉搜索树的构造,那就不得不说二叉搜索树不平衡的极端情况,极端情况下二叉搜索树会退化成一个链表,导致操作效率大幅降低。这也和快速排序是一样的道理,特别是数组元素都相同的情况下,时间复杂度会大幅上升。

为了避免这种情况,我们要引入随机性:

用代码表示就是(取left ~ right 区间的随机数,加上偏移量left):

int key = nums[new Random().nextInt(r - l + 1) + l];

快排思路: 

从数组中随机取一个元素key,将数组划分为三个区域,区域① < key ,区域 ② = key ,

区域③ > key,然后排序①区间和②区间即可

代码详解:

class Solution {public int[] sortArray(int[] nums) {quickSort(nums,0,nums.length - 1);return nums;}public void quickSort(int[] nums,int l,int r){if(l >= r) return ;//设置一个随机数,然后将数组分为三块int key = nums[new Random().nextInt(r - l + 1) + l];int left = l - 1,cur = l,right = r + 1;while(cur < right){if(nums[cur] < key){swap(nums,++left,cur++);}else if(nums[cur] == key){cur++;}else{swap(nums,--right,cur);}}//在接着往后面找,此时数组区域[l,left] [left + 1,right - 1] [right,r]quickSort(nums,l,left);quickSort(nums,right,r);}public void swap(int[] nums,int i,int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}
}

运行结果:

三.数组中的第k个最大元素:

题目链接:215. 数组中的第K个最大元素 - 力扣(LeetCode)

解法一:快速选择算法

思路:

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

 代码详解:

class Solution {public int findKthLargest(int[] nums, int k) {//快速选择算法,返回第k大的元素int res = quickSort(nums,0,nums.length - 1,k);return res;}public int quickSort(int[] nums,int l,int r,int k){//当只有一个元素或则区间不存在时,直接返回if(l >= r) return nums[l];//数组分三块 [l,left][left + 1,right - 1][right,r]int key = nums[new Random().nextInt(r - l + 1) + l];int left = l - 1,cur = l,right = r + 1;while(cur < right){if(nums[cur] < key){swap(nums,++left,cur++);}else if(nums[cur] == key){cur++;}else{swap(nums,--right,cur);}}//分别对a b c 三个区间做判断,合适的区间int b = right - left - 1,c = r - right + 1;if(c >= k) return quickSort(nums,right,r,k);else if(b + c >= k) return key;//如果都不是,就去[l,left]区间找k - b - c大的元素else return quickSort(nums,l,left,k - b - c);}public void swap(int[] nums,int i,int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}
}

运行结果: 

解法二:简单粗暴优先级队列

代码详解:

class Solution {public int findKthLargest(int[] nums, int k) {PriorityQueue<Integer> heap = new PriorityQueue<>((o1,o2)->{return o2.compareTo(o1);});for(int i = 0;i < nums.length;i++){heap.offer(nums[i]);}int res = 0;for(int i = 0;i < k;i++){res = heap.poll();}return res;}
}

 运行结果:

 四.库存管理Ⅲ:

题目链接:LCR 159. 库存管理 III - 力扣(LeetCode)

解法一:快速选择

 思路:

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

 代码详解:

class Solution {public int[] inventoryManagement(int[] stock, int k) {quickSort(stock,0,stock.length - 1,k);int[] res = new int[k];for(int i = 0;i < k;i++){res[i] = stock[i];}return res;}public void quickSort(int[] nums,int l,int r,int k){if(l >= r) return ;//随机取数int key = nums[new Random().nextInt(r - l + 1) + l];int left = l - 1,cur = l,right = r + 1;while(cur < right){if(nums[cur] < key){swap(nums,++left,cur++);}else if(nums[cur] == key){cur++;}else{swap(nums,--right,cur);}}//寻找区间最小k个值[l,left] [left + 1,right - 1][right,r]int a = left - l + 1,b = right - left - 1;if(a > k) quickSort(nums,l,left,k);else if(a + b >= k) return ;else quickSort(nums,right,r,k - a - b);}public void swap(int[] nums,int i,int j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}
}

运行结果:

解法二:简单粗暴排序

代码详解:

class Solution {public int[] inventoryManagement(int[] stock, int cnt) {Arrays.sort(stock);int[] res = new int[cnt];for(int i = 0;i < cnt;i++){res[i] = stock[i];}return res;}
}

运行结果:

解法三:简单粗暴优先级队列

代码详解:

class Solution {public int[] inventoryManagement(int[] stock, int cnt) {PriorityQueue<Integer> heap = new PriorityQueue<>();for(int i = 0; i < stock.length; i++){heap.offer(stock[i]);}int[] res = new int[cnt];for(int i = 0;i < cnt;i++){res[i] = heap.poll();}return res;}
}

参考资料:

 五大常用算法之一:分治算法 - Will_Don - 博客园 (cnblogs.com)

《labuladong算法笔记》

封面来自:《hello 算法》

结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!

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

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

相关文章

Unity扩展编辑器功能的特性

1.添加分组标题 用于在Unity的Inspector视图中为属性或变量组创建一个自定义的标题或头部&#xff0c;有助于在Inspector中组织和分类不同的属性&#xff0c;使其更易于阅读和管理。 [Header("Common Properties")] public float MouseSensitivity 5; public float…

微服务中的Docker详细学习

Docker的个人理解 首先我对于Docker的理解分为两部分&#xff0c;第一是对名字上的理解&#xff0c;我们都知道docker的英文翻译是“码头工人”的意思&#xff0c;所以我们也可以理解为docker是码头上的一个个集装箱的使用。这也与他的图标很相似。其次我是对于其功能上的理解&…

Redis 高可用(理论)

目录 Redis 高可用 Redis 持久化 RDB 持久化 触发条件 手动触发 自动触发 ##其他自动触发机制## 执行流程 启动时加载 AOF 持久化 执行流程 &#xff08;1&#xff09;命令追加(append) &#xff08;2&#xff09;文件写入(write)和文件同步(sync) &#xff08;3&…

帝国CMS(EmpireCMS)漏洞复现

简介 《帝国网站管理系统》英文译为Empire CMS&#xff0c;简称Ecms&#xff0c;它是基于B/S结构&#xff0c;且功能强大而帝国CMS-logo易用的网站管理系统。 帝国CMS官网&#xff1a;http://www.phome.net/ 参考相关漏洞分析文章&#xff0c;加上更详细的渗透测试过程。 参考…

snat、dnat和firewalld

目录 概述 SNAT源地址转换 DANT目的地址转换 抓包 firewalld 端口管理 概述 snat &#xff1a;源地址转换 内网——外网 内网ip转换成可以访问外网的ip 也就是内网的多个主机可以只有一个有效的公网ip地址访问外部网络 DNAT&#xff1a;目的地址转发 外部用户&#…

人工智能导论速成笔记

文章目录 前言考试题型第一章、人工智能导引 (10分 )课后习题第二章、Python基础 (10分 )*文件读写NumPy的使用Python绘图基础第三章、机器学习初步(15分 )逻辑回归分类(Logistic Regression)*,3.5线性回归预测(Linear Regression)*,3.6 、3.7、 3.8聚类 3.9第四章、自然语言…

一文带你了解乐观锁和悲观锁的本质区别!

文章目录 悲观锁是什么&#xff1f;乐观锁是什么&#xff1f;如何实现乐观锁&#xff1f;什么是CAS应用局限性ABA问题是什么&#xff1f; 悲观锁是什么&#xff1f; 悲观锁它总是假设最坏的情况&#xff0c;它会认为共享资源在每次被访问的时候就会出现线程安全问题&#xff0…

JVM调优(一)——JVM调优诊断工具详解

最近项目要生产上线&#xff0c;正在做压测性能测试&#xff0c;开始进行一些性能瓶颈分析&#xff0c;记得上一次做性能分析优化&#xff0c;还是国网项目&#xff0c;针对Kafka,Canal,ES,服务&#xff0c;数据库等一系列的排查分析&#xff0c;后面打算补一下总结内容&#x…

安全和加密常识(6)Base64编码方式

文章目录 什么是 Base64编码原理编解码示例应用什么是 Base64 Base64 是一种用于将二进制数据编码为仅包含64种ASCII字符的文本格式的编码方法,注意,它不是加密算法。它设计的目的主要是使二进制数据能够通过只支持文本的传输层(如电子邮件)进行传输。Base64常用于在需要处…

Windows系统下文件夹权限详解

文章目录 问题描述文件夹属性 问题描述 今天在Win10系统下&#xff0c;实现文件夹设置权限&#xff0c;具体的方案的涉及到我们公司内部的一款加密软件&#xff0c;不太方便透漏&#xff0c;借此机会&#xff0c;我也重新的回顾下windows系统下的文件夹权限 文件夹属性 打开…

vue3+Ts封装axios网络请求

1.安装axios npm i axios 在package.json中检查axios是否安装成功 "dependencies": {"axios": "^1.7.2","vue": "^3.4.29","vue-router": "^4.4.0"}, 2.新建文件 新建文件utils/request.ts import…

Java 并发编程常见问题

1、线程状态它们之间是如何扭转的&#xff1f; 1、谈谈对于多线程的理解&#xff1f; 1、对于多核CPU&#xff0c;多线程可以提升CPU的利用率&#xff1b; 2、对于多IO操作的程序&#xff0c;多线程可以提升系统的整体性能及吞吐量&#xff1b; 3、使用多线程在一些场景下可…

鸿蒙开发设备管理:【@ohos.multimodalInput.inputDevice (输入设备)】

输入设备 输入设备管理模块&#xff0c;用于监听输入设备连接、断开和变化&#xff0c;并查看输入设备相关信息。比如监听鼠标插拔&#xff0c;并获取鼠标的id、name和指针移动速度等信息。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&…

【算法专题--栈】用队列实现栈 -- 高频面试题(图文详解,小白一看就懂!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐两个队列实现栈 &#x1f95d;解题思路 &#x1f34d;案例图解 ⭐用一个队列实现栈 &#x1f347;解题思路 &#x1f34d;案例图解 四、总结与提炼 五、共勉 一、前言 用队列实现栈 这道题&#xff0c;可以说是--栈…

002-基于Sklearn的机器学习入门:回归分析(上)

本节及后续章节将介绍机器学习中的几种经典回归算法&#xff0c;所选方法都在Sklearn库中聚类模块有具体实现。本节为上篇&#xff0c;将介绍基础的线性回归方法&#xff0c;包括线性回归、逻辑回归、多项式回归和岭回归等。 2.1 回归分析概述 回归&#xff08;Regression&…

《昇思25天学习打卡营第14天 | 昇思MindSpore基于MindNLP+MusicGen生成自己的个性化音乐》

14天 本节学了基于MindNLPMusicGen生成自己的个性化音乐。 MusicGen是来自Meta AI的Jade Copet等人提出的基于单个语言模型的音乐生成模型&#xff0c;能够根据文本描述或音频提示生成高质量的音乐样本。 MusicGen模型基于Transformer结构&#xff0c;可以分解为三个不同的阶段…

⭐ UI自动化工具轻松实现微信消息提醒 ⚡

&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f; 演示效果 &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f; &#x1f605;&#x1f605;&#x1f605;&#x1f605;&#x1f605;&#x1f605; Python安装…

STM32 SWD烧写

最小电路 stm32f103x 内部已经集成了振荡电路&#xff0c;可以省略&#xff1b;rst引脚电路&#xff0c;可以省略&#xff0c;boot0,boot1不需要设置 正常烧录 -------------------------------------------------------------------STM32CubeProgrammer v2.9.0 …

使用 go-control-plane 自定义服务网格控制面

写在前面 阅读本文需要最起码了解envoy相关的概念 本文只是一个类似于demo的测试&#xff0c;只为了学习istio&#xff0c;更好的理解istio中的控制面和数据面&#xff08;pilot -> proxy&#xff09;是如何交互的&#xff0c;下图的蓝色虚线 先说go-control-plane是什么…

nginx 1024 worker_connections are not enough while connecting to upstream

现象 请求api响应慢&#xff0c;甚至出现504 gateway timeout&#xff0c;重启后端服务不能恢复&#xff0c;但重启nginx可以恢复。 解决方案 worker_connections使用了默认值 1024&#xff0c;当流量增长时&#xff0c;导致连接不够 在nginx.conf中修改连接数就可以了&…