LeetCode912排序数组(快速排序机及其优化详解)

news2024/11/24 14:34:45

LeetCode912排序数组(快速排序及其优化详解)

文章目录

  • LeetCode912排序数组(快速排序及其优化详解)
    • Abstract
    • 基本快速排序
    • 快速排序思路总结以及优化
    • 优化思路
      • 针对渐进有序数组
      • 针对相同元素较多的数组
    • Code
    • 参考文献

Abstract

我首先试图使用快速排序算法解答此题,无奈超过时间限制。超出时间限制的两个测试用例是:1.数组中的所有元素均相同 2.数组已经是被排好序的升序数组。针对第一个测试用例,可以使用三路指针法(即对和主元相等的元素进行单列一块)。对第二个测试用例,可以使用随机选主元的方法来实现(使用c++的rand()函数 %待排序数组长度 + 待排序数组起始下标)。在本文中,我首先介绍了基本的快速排序方法,然后介绍了两种优化思路。最后,我同时使用了两种优化思路,终于通过了Leetcode912.

基本快速排序

与归并排序一样,快速排序也使用了分治思想。下面是对一个典型的子数组A[p…r]进行快速排序的三步分治过程。

分解:数组A[p…r]被划分为两个(可能为空)的子数组A[p…q-1]和A[q+1…r],使得A[p…q-1]中的每一个元素都小于等于A[q],而A[q]也小于等于A[q+1…r]中的每个元素。其中,计算下标q也是划分过程的一部分。

**解决:**通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行排序。

合并: 因为子数组都是原址排序的,所以不需要合并操作:数组A[p…r]已经有序。

快速排序的伪代码

QuickSort(A, p,r)

​ if p<r

​ q = PARTITION(A, p,r)

​ QuickSort(A, p, q-1)

​ QuickSort(A, q+1, r)

为了排序一个数组A的全部元素,初始调用是QUICKSORT(A, 1, A.length)

数组的划分

算法的关键部分是PARTITION过程,它实现了对子数组A[p…r]的原址重排。

PARTITION(A, p,r)

​ x = A[r]

​ i = p-1

​ for j = p to r-1

​ if(A[j]<=x)

​ i++;

​ swap(A[j], A[i])

​ swap(A[i+1], A[r])

​ return i+1;

掌握该算法的关键点掌握哪些量是变化的,哪些量是不变化的。变化的是两个指针i, j, 不变的是p和r. 我们只需要知道在扫描的过程中,如何变i和j即可。

我们需要保证的是:

  • A[p…i]是<=x
  • A[i+1…j-1]是>=x.
  • A[j…r-1]是未知的
  • A[r]是等于x的。

如果A[j]<=x, 则需要将该元素放到小于等于x的部分去,首先i++, 然后将A[j]和A[i]进行交换,然后j++;

如果A[j]>x, 则只需要j++即可。

当我们扫描到A[r]时,就需要将该分界元素放到我们为分界元素所设定的位置上,即i+1的位置。所以将A[r]和A[i+1]交换,然后返回i+1;

快速排序思路总结以及优化

  • 基本思路:快速排序每一次都排定一个元素,然后递归地排它左边的部分和右边的部分,依次进行下去,直到数组有序。

  • 如图所示:这张图很好地体现了快速排序的本质其实是一个递归树,

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOIWXXyb-1687253345354)(https://pic.leetcode.cn/1678475287-xpnAxX-%E5%9F%BA%E7%A1%80%E5%BF%AB%E6%8E%92%20-%20%E5%89%AF%E6%9C%AC.jpg)]

该划分存在的问题

1.如果该数组所有元素都相同,且元素数量特别多,则很可能会存在超时的情况。例如[2,2,2,2,2], 则调用完之后会有[2,2,2,2],然后是[2,2,2], 然后是[2,2],最后是[2]. 则时间复杂度为 O ( ∑ i = 1 n ) = O ( n 2 ) O(\sum_{i=1}^n) = O(n^2) O(i=1n)=O(n2). 此时基本排序的树为仅有一边的树。

2.如果数组元素基本已经排序好, 例如,1到50000的一个已经升序排列好的数组,对于这个数组,基本快排的划分为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1DtPzVDq-1687253345356)(2023-6-19快速排序详解/1.jpg)]

优化思路

对于这种树形结构,我们的优化可以从两个方面入手,一是尽可能使得树的两端平衡,二是尽可能减少树的高度。

针对渐进有序数组

  • 随机取得pivot, 树的两端的会变得更加平衡。

针对相同元素较多的数组

三路快排

  • 三路快排(三指针法),把等于pivot元素的所有元素放在分割区间的中间,也就是说我们每次递归确定的是这个元素以及和它相等的元素的位置,大量元素相等的情况下,递归区间大大减少。
  • 数组划分:
    • A[p…i] < x, A[i+1…j-1]==x, A[j…k-1] 未知, A[k…r-1]>x. A[r] == x.

Code

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        srand((unsigned)time(NULL));
        int size_nums = nums.size();
        quicksort(nums, 0, size_nums-1);
        return nums;
    }

    vector<int> partition(vector<int>& nums, int p, int r){
        int rand_index = rand() % (r-p+1)+p;
        int x = nums[rand_index];
        swap(nums[rand_index], nums[r]);
        int i = p -1;
        int j = p;
        int k = r;
        //循环不变量
        // nums[p..i] < x
        // nums[i+1..j-1] equals x
        // nums[j..k-1] unknown
        // nums[k..r-1] >x
        // nums[r] equals x
        // 循环不变量在第一轮迭代之前是成立的。
        while(j<=k-1){
            if(nums[j]<x){
                i++;
                swap(nums[j], nums[i]);
                j++;
            }
            else if(nums[j] == x){
                j++;
            }
            else{
                k--;
                swap(nums[j], nums[k]);
            }
        }

        swap(nums[k], nums[r]);
        vector<int> results;
        results.push_back(i);
        results.push_back(k);
        return results;
    }

    void quicksort(vector<int>& nums, int p, int r){
        if(p>=r){
            return;
        }

        if(p<r){
            //随机选取法
            vector<int> partitions = partition(nums, p, r);
            quicksort(nums, p, partitions[0]);
            quicksort(nums, partitions[1], r);
        }
    }
};

参考文献

[1] https://leetcode.cn/problems/sort-an-array/solution/kuai-su-pai-xu-you-hua-zhen-dui-duo-zhon-ryq4/

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

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

相关文章

【Python 下载,Anaconda下载,环境变量配置,两个python不同版本使用环境变量配置切换】

我再下载Anaconda之前&#xff0c;自己安装了一个Python3.11.配置环境变量之后&#xff0c;查看python版本&#xff1a; 下载好Anaconda3之后&#xff0c;将环境变量提到之前的前面&#xff0c;再使用CMD,查看就是Anaconda自带的Python版本&#xff0c;该版本有就有很多的第三方…

大模型与人类的未来 | 基于认知神经科学的大模型论坛精彩回顾

导读 6 月 10 日&#xff0c;智源大会“基于认知神经科学的大模型论坛”召开&#xff0c;本次论坛邀请到了认知神经、脑科学领域非常有建树的专家&#xff0c;深度讨论大模型的能力与局限性&#xff0c;包括对未来人工智能发展方向的讨论。论坛主席是清华大学脑与智能实验室首席…

全网最牛最全Postman接口测试: postman设置接口关联,postman实现参数化

postman设置接口关联 在实际的接口测试中&#xff0c;后一个接口经常需要用到前一个接口返回的结果&#xff0c; 从而让后一个接口能正常执行&#xff0c;这个过程的实现称为关联。 在postman中实现关联操作的步骤如下&#xff1a; 1、利用postman获取上一个接口指定的返回值…

2023年5月青少年机器人技术等级考试理论综合试卷(五级)

青少年机器人技术等级考试理论综合试卷&#xff08;五级&#xff09; 分数&#xff1a; 100 题数&#xff1a; 30 一、 单选题(共 20 题&#xff0c; 每题 4 分&#xff0c; 共 80 分) 1.ESP32 for Arduino&#xff0c; 下列程序的运行结果是&#xff1f; &#xff08; &#x…

GAMES101笔记 Lecture05 光栅化1(Triangles)

目录 Perspective Projection(透视投影)Canonical Cube to Screen(从标准立方体到屏幕)What is a screen(什么是屏幕)? Rasterization: Drawing to Raster Displays(如何在光栅设备上画东西)Triangles - Fundamental Shape Primitives(三角形-基本形状的基元)Why triangles?&…

node从头到尾实现简单编译器

介绍 本文用node实现了一个简单的编译器mccompiler&#xff0c;主要用于学习&#xff0c;笔者能力和精力有限&#xff0c;如有不当&#xff0c;还请指出 原文地址&#xff1a;原文地址 项目地址&#xff1a;项目地址 本文涉及&#xff1a;编译器的词法分析&#xff0c;抽象语义…

应用程序传递数据给驱动和驱动操作LED灯

目录 1. 应用程序将数据传递给驱动 1.1. 函数分析 1.2. 编写驱动.c文件 1.3. 编写编译驱动的makefile文件 1.4. 执行make命令&#xff0c;并安装驱动&#xff0c;生成设备文件 1.5. 写应用层.c文件 1.6. 执行可执行文件验证 2. 驱动操作LED灯 2.1. 函数分析 2.2. 手册…

【C语言】第一个C语言项目——“猜数字”游戏(内附源码)

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello米娜桑&#xff0c;这里是君兮_&#xff0c;今天又抽空为大家更新我们的主线0基础C语言啦&#xff01;鉴于最近讲解了非常多的选择语句与循环语句&#xff0c;咱们今天就来讲讲两者结合的一个简单的实战应用。 同时…

Python Locust全过程使用代码详解

下方查看历史精选文章 重磅发布 - 自动化框架基础指南pdfv1.1大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 Python locust 是一个基于 Python 的开源负…

MKS SERVO4257D 闭环步进电机_系列9 上位机通讯示例

第1部分 产品介绍 MKS SERVO 28D/35D/42D/57D 系列闭环步进电机是创客基地为满足市场需求而自主研发的一款产品。具备脉冲接口和RS485/CAN串行接口&#xff0c;支持MODBUS-RTU通讯协议&#xff0c;内置高效FOC矢量算法&#xff0c;采用高精度编码器&#xff0c;通过位置反馈&a…

视觉SLAM十四讲——ch13实践(设计SLAM系统)

视觉SLAM十四讲——ch13的实践操作及避坑 1. 实践操作前的准备工作2. 实践过程2.1 运行测试程序2.2 运行00数据集2.3 更改代码画出运动轨迹 3. 遇到的问题及解决办法3.1 cmake ..时出现的问题3.2 make时出现的问题3.3 头文件下红色报错 1. 实践操作前的准备工作 下载Kitti数据…

使用dat.gui更改three.js中的物体变量

一、dat.gui介绍 gui是一种JavaScript库&#xff0c;用于创建可视化控件和调试工具。它是dat.gui的简称。dat.gui是一个用于在Web应用程序中创建可定制GUI的JavaScript库。它可以轻松创建滑块、复选框、颜色选择器等控件&#xff0c;用户可以直接在GUI上进行交互和调整。dat.g…

一起来看看 K-verse LAND 销售活动中的合作伙伴给大家的祝福吧~

K-verse 是 The Sandbox 中的韩国内容主题空间&#xff0c;自去年 12 月首次推出以来&#xff0c;已吸引多家合作伙伴加入。此外&#xff0c;现有的合作伙伴公司和品牌正在积极准备以新的形式展示元宇宙内容。 这里有着许多可能性&#xff0c;K-verse LAND 销售活动是不是让你们…

Tomcat及项目部署

一、Tomcat是什么&#xff1f; Tomcat 是基于 Java 实现的⼀个开源免费, 也是被⼴泛使⽤的 HTTP 服务器。 二、下载安装 官⽅⽹站&#xff1a;https://tomcat.apache.org/ 选择其中的 zip 压缩包, 下载后解压缩即可. 解压缩的⽬录最好不要带 "中⽂" 或者 特殊符号…

vue-cli 如何修改默认环境变量名称

比如想要修改开发环境 NODE_ENV 的默认值 &#xff1f; 1. 新建文件 .env.development 2. 在 packjson.json 的 script 中添加一行代码 --mode [文件 env 后面的环境名称] "dev": "vue-cli-service serve --mode development", 3. 然后 npm run dev 环境变…

JavaScript ES12新特性有哪些?

文章目录 导文Promise.any()WeakRef 和 FinalizationRegistry数字分隔符String.prototype.replaceAll()Logical Assignment Operators数字类型的新增方法私有字段和方法 导文 JavaScript ES12&#xff08;也称为ECMAScript 2022&#xff09;是JavaScript的最新版本&#xff0c;…

如何解决报错:nginx error!

目录 Nginx报错问题 nginx error! The page you are looking for is not found. Website Administrator 解决方法 Nginx报错问题 当访问搭建好的Nginx服务网站时 有以下报错 nginx error! The page you are looking for is not found. Website Administrator Someth…

猪齿鱼开源发布2.0版本:DevOps能力全面升级,研发效能显著提升,欢迎即刻体验!

近日&#xff0c;甄知科技猪齿鱼Choerodon数智化开发管理平台正式发布了开源2.0版本&#xff01; 开源发布会上&#xff0c;甄知产研团队、业内伙伴和社区开发者们齐聚一堂&#xff0c;共同见证猪齿鱼开源2.0的重磅发布&#xff01;发布会由上海甄知科技创始合伙人兼CTO张礼军先…

前端添加代理通过nginx进行转发解决跨域

记录在项目中遇到跨域并进行解决的方案 解决方案 记录在项目中遇到跨域并进行解决的方案前端代理部分nginx转发配置origin限制,修复CORS跨域漏洞 前端代理部分 代理后页面请求地址截图&#xff1a; 这里地址栏的地址是&#xff1a;http://127.0.0.1:13908 调用登录接口请求地…

OrCAD Capture 元件位号Part Reference有下划线

原因&#xff1a; 提示用户曾经修改过原理图封装。 现象&#xff1a; USB20_12 解决办法&#xff1a; 对着元器件右键>User Assigned Reference > Uset&#xff0c;即可消除下划线。 修改后&#xff1a;