快速排序(二叉树的前序递归遍历思想)

思路

之前我们从选择排序,到选择排序的稳定性优化,到冒泡排序,到插入排序,到插入排序的提前截止时间,到希尔排序,虽然逐步一直都在优化,但是时间复杂度还是N得平方,力扣提交的结果一直都是时间超时,因为时间复杂度并没有发生量级级别的减少,都是通过常规的优化思维,说白一点,就是没有创新的优化点,都是一步一步,一点一点优化,想方设法能能提高一点效率就提高一点。
那么从快速排序就是要开始坐飞机了往前冲了,直接打破一个量级的时间复杂度,从N的平方,到Nlogn,N就是二叉树的深度,logn就是每一层的时间复杂度。
为什么说快速排序是结合了二叉树前序递归思想的排序,后面我把快速排序的代码写出来吗,你对比一下二叉树的前序遍历,结构基本都是差不多的。
快速排序的解题思路就是:一般默认选择第一个数组元素作为起点,将第一个元素处理一下,使得左边的元素都小于它,右边的元素都大于它。第二就开最左右的数组继续处理,左边的数据选择当前第一个元素再左边找到位置是的左边都小于它,右边的都大于它,右边同理。你看这不就是二叉树的前序递归遍历吗?
接下来直接看代码,如果说你明白了在快排中使用到了二叉树的前序遍历思想,那你成功的解决了50的问题,剩下的50%是看你嫩不能解决数组中的一个点,如何找到它所在的位置,并且交换好数据吗,这个还需要主要的是一个数组的边界问题(如果数组题好好刷了,知道数组边界的处理,不混乱),那第二个难点也就不是什么难点,我还是讲一下找到中间位置的函数的思路吧,但是边界为就不讲了,这块儿还是有点技巧的,回头再来刷这个题目的时候再看吧

代码

class Solution {public int[] sortArray(int[] nums) {sort(nums,0,nums.length-1);return nums;}//定义一个递归遍历的函数sortvoid sort(int[] nums,int lo,int hi){if(lo > hi){return;}int p = partition(nums, lo, hi);sort(nums,lo,p-1);sort(nums,p+1,hi);}//定义一个找到位置的partition函数int partition(int[] nums, int lo, int hi){int pivot = nums[lo];// 关于区间的边界控制需格外小心,稍有不慎就会出错// 我这里把 i, j 定义为开区间,同时定义:// [lo, i) <= pivot;(j, hi] > pivot// 之后都要正确维护这个边界区间的定义int i = lo + 1, j = hi;// 当 i > j 时结束循环,以保证区间 [lo, hi] 都被覆盖while (i <= j) {while (i < hi && nums[i] <= pivot) {i++;// 此 while 结束时恰好 nums[i] > pivot}while (j > lo && nums[j] > pivot) {j--;// 此 while 结束时恰好 nums[j] <= pivot}if (i >= j) {break;}// 此时 [lo, i) <= pivot && (j, hi] > pivot// 交换 nums[j] 和 nums[i]swap(nums, i, j);// 此时 [lo, i] <= pivot && [j, hi] > pivot}// 最后将 pivot 放到合适的位置,即 pivot 左边元素较小,右边元素较大swap(nums, lo, j);return j;}// 原地交换数组中的两个元素private static void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}

在这里插入图片描述
这个运行后还是超出运行限制,到底是哪里还可以继续优化呢,肯定是可以的,我们先不纠结了,能和面试官谈到这里,说不定他还没有懂得深的。差不多了,优化的点我先提一下,就是在上面的基础上加了一个洗牌算法
直接看代码:

class Solution {public int[] sortArray(int[] nums) {// 为了避免出现耗时的极端情况,先随机打乱shuffle(nums);sort(nums,0,nums.length-1);return nums;}//定义一个递归遍历的函数sortvoid sort(int[] nums,int lo,int hi){if(lo > hi){return;}int p = partition(nums, lo, hi);sort(nums,lo,p-1);sort(nums,p+1,hi);}//定义一个找到位置的partition函数int partition(int[] nums, int lo, int hi){int pivot = nums[lo];// 关于区间的边界控制需格外小心,稍有不慎就会出错// 我这里把 i, j 定义为开区间,同时定义:// [lo, i) <= pivot;(j, hi] > pivot// 之后都要正确维护这个边界区间的定义int i = lo + 1, j = hi;// 当 i > j 时结束循环,以保证区间 [lo, hi] 都被覆盖while (i <= j) {while (i < hi && nums[i] <= pivot) {i++;// 此 while 结束时恰好 nums[i] > pivot}while (j > lo && nums[j] > pivot) {j--;// 此 while 结束时恰好 nums[j] <= pivot}if (i >= j) {break;}// 此时 [lo, i) <= pivot && (j, hi] > pivot// 交换 nums[j] 和 nums[i]swap(nums, i, j);// 此时 [lo, i] <= pivot && [j, hi] > pivot}// 最后将 pivot 放到合适的位置,即 pivot 左边元素较小,右边元素较大swap(nums, lo, j);return j;}// 原地交换数组中的两个元素private static void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}// 洗牌算法,将输入的数组随机打乱private static void shuffle(int[] nums) {Random rand = new Random();int n = nums.length;for (int i = 0 ; i < n; i++) {// 生成 [i, n - 1] 的随机数int r = i + rand.nextInt(n - i);swap(nums, i, r);}}
}

加上洗牌算法果然就通过了
在这里插入图片描述
接下来就继续分析一下,为什么加了一个洗牌算法就能提交通过呢,这里面到底优化什么?
这个问题要从快速排序的构造思想和极端情况两方面进行分析:
首先是上面我们提到的快速排序的构造思想就是二叉数的前序遍历构造思想,不是非常极端的二叉树情况,那么快速排序正常的复杂度就是NlogN,但是如果运气不好,出现了前序遍历后的二叉树呈现一边倒的趋势,这样的话,复杂度就又变成最坏的情况,N的平方了。所以提交才没有过。
之后我们又采用了洗牌算法,先把数组打乱,这样就不会出现极端情况了,至于洗牌算法是什么思想,怎么实现,后续慢慢道来。

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

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

相关文章

Redis 面试篇

Redis相关面试题 缓存三剑客 面试官&#xff1a;什么是缓存穿透 ? 怎么解决 ? 缓存穿透是指查询一个一定不存在的数据&#xff0c;如果从存储层查不到数据则不写入缓存&#xff0c;这将导致这个不存在的数据每次请求都要到 DB 去查询&#xff0c;可能导致 DB 挂掉。这种情况…

群晖DS223 Docker搭建为知笔记

群晖DS223 Docker搭建为知笔记&#xff0c;打造你的专属知识宝库 一、引言 在数字化信息爆炸的时代&#xff0c;笔记软件成为了我们管理知识、记录灵感的得力助手。为知笔记&#xff0c;作为一款专注于工作笔记和团队协作的云笔记产品&#xff0c;以其丰富的功能和便捷的使用体…

Linux网络之数据链路层协议

目录 数据链路层 MAC地址与IP地址 数据帧 ARP协议 NAT技术 代理服务器 正向代理 反向代理 上期我们学习了网络层中的相关协议&#xff0c;为IP协议。IP协议通过报头中的目的IP地址告知了数据最终要传送的目的主机的IP地址&#xff0c;从而指引了数据在网络中的一步…

分类评价指标

基础概念解释 TP、TN、FP、FN 这里T是True&#xff0c;F是False&#xff0c;P为Positive&#xff0c;N为Negative TP&#xff1a;被模型正确地预测为正样本&#xff08;原本为正样本&#xff0c;预测为正样本&#xff09; TN&#xff1a;被模型正确地预测为负样本&#xff0…

LeetCode 哈希章节

简单 1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。 你可以按任意顺序返…

WLAN(无线局域网)安全

WLAN安全涉及到保护无线局域网免受各种威胁和攻击&#xff0c;以确保数据的保密性、完整性和可用性。以下是关于WLAN安全的多方面介绍&#xff1a; 一、主要安全威胁 窃听&#xff1a;攻击者利用特殊设备监听无线信号&#xff0c;获取传输中的数据&#xff0c;如用户的账号密…

江科大51单片机笔记【11】AT24C02(I2C总线)

一、存储器 1.介绍 RAM的特点是存储速度特别快&#xff0c;但是掉电会丢失&#xff1b;ROM的特点是存储速度特别慢&#xff0c;但是掉电不会丢失 SRAM是所有存储器最快的&#xff0c;一般用于电脑的CPU高速缓存&#xff0c;容量相对较少&#xff0c;成本较高&#xff1b;DRAM…

【C++指南】一文总结C++类和对象【中】

&#x1f31f; 各位看官好&#xff0c;我是egoist2023&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; &#x1f680; 今天来学习C类和对象的语法知识。注意&#xff1a;在本章节中&#xff0c;小编会以Date类举例 &#x1f44d; 如果觉得…

PgSql 操作技巧

1、查询数据导出csv数据 \COPY (SELECT w.* from t_sys_warn w ) TO /home/cuadmin/warn_output.csv WITH CSV HEADER;2、导出sql Insert语句 pg_dump -U 用户名 -h 主机名 -p 端口号 -d 数据库名 --inserts -t 表名 > 导出文件.sqlpg_dump -U username -d dbname -t tabl…

Unity ES3保存类的问题

有以下一个物品类 public class Item_Base//基础物品 { public string ID; private Attribute_Data Item_attribute new(); } 当使用ES3保存这个类时&#xff0c;Item_attribute的数据不会被保存&#xff0c;因为它是私有private ES3保存类时&#xff0c;只会保存…

react基本功

useLayoutEffect useLayoutEffect 用于在浏览器重新绘制屏幕之前同步执行代码。它与 useEffect 相同,但执行时机不同。 主要特点 执行时机:useLayoutEffect 在 DOM 更新完成后同步执行,但在浏览器绘制之前。这使得它可以在浏览器渲染之前读取和修改 DOM,避免视觉上的闪烁…

Spring Boot笔记(上)

01 概要 Spring Boot 是 Java 领域最流行的 快速开发框架&#xff0c;专为简化 Spring 应用的初始搭建和开发而设计。 一、Spring Boot 解决了什么问题&#xff1f; 传统 Spring 痛点 • 繁琐的 XML 配置 • 需要手动管理依赖版本 • 部署依赖外部 Web 服务器&#xff08;如 …

目标检测YOLO实战应用案例100讲-基于毫米波雷达的多目标检测 (续)

目录 3.2 改进的CFAR目标检测算法 3.3 算法步骤描述 3.4 实验结果与分析 基于VGG16-Net的毫米波雷达目标检测算法 4.1 VGG16-Net网络模型 4.2 改进VGG16-Net网络的目标检测算法 4.3 算法步骤描述 4.4 实验结果与分析 知识拓展 基于毫米波雷达的多目标检测:使…

gitsubtree怎么添加新的子仓库

要使用 git subtree 添加一个新的子仓库&#xff0c;可以按照以下步骤操作&#xff1a; 1. 添加子仓库 使用 git subtree add 命令将子仓库的内容添加到主仓库的指定目录中。命令格式如下&#xff1a; git subtree add --prefix<子目录路径> <子仓库地址> <子…

文本转语音-音画适时推送rtsp并播放

文本语音 rtsp适时播放叫号系统的底层逻辑 发布Linux, unix socket 和window win32做为音频源的 python10下的(ffmpeg version 7.1) 可运行版本. 这两天在弄这个&#xff0c;前2篇是通过虚拟声卡&#xff0c;达到了最简单的一个逻辑&#xff0c;播放文本就从声卡发声&#xff0…

从0开始的操作系统手搓教程33:挂载我们的文件系统

目录 代码实现 添加到初始化上 上电看现象 挂载分区可能是一些朋友不理解的——实际上挂载就是将我们的文件系统封装好了的设备&#xff08;硬盘啊&#xff0c;SD卡啊&#xff0c;U盘啊等等&#xff09;&#xff0c;挂到我们的默认分区路径下。这样我们就能访问到了&#xff…

【图片批量转换合并PDF】多个文件夹的图片以文件夹为单位批量合并成一个PDF,基于wpf的实现方案

项目背景: 多个图片分布在不同文件夹,如何以文件夹为单位批量合并成一个PDF,还要保证文件夹里面图片大小和顺序 实现功能: 1、单张图片的转换PDF:一张图临时转一下 2、多张图片转换成PDF:多张图单独转成PDF 3、多级目录多张图转换成PDF:多级目录多张图单独转成多个PDF…

如何用Kimi生成PPT?秒出PPT更高效!

做PPT是不是总是让你头疼&#xff1f;&#x1f629; 快速制作出专业的PPT&#xff0c;今天我们要推荐两款超级好用的AI工具——Kimi 和 秒出PPT&#xff01;我们来看看哪一款更适合你吧&#xff01;&#x1f680; &#x1f947; Kimi&#xff1a;让PPT制作更轻松 Kimi的生成效…

从 MongoDB 到 TDengine,沃太能源实现 18 倍写入性能提升

导读 沃太能源是国内领先储能设备生产厂商&#xff0c;数十万储能终端遍布世界各地。此前使用 MongoDB 存储时序数据&#xff0c;但随着设备测点增加&#xff0c;MongoDB 在存储效率、写入性能、查询性能等方面暴露出短板。经过对比&#xff0c;沃太能源选择了专业时序数据库 …

数据库基本建表操作

1.登录数据库并创建数据库db_ck 创建完成后使用到我们创建的数据库。 2.创建表t_hero 根据hero属性包括&#xff08;id&#xff0c;name&#xff0c;nickname&#xff0c;age&#xff0c;gender&#xff0c;address&#xff0c;weapon&#xff0c;types&#xff09; 创建完…