【算法】分治 - 快速排序

news2025/1/12 12:15:27



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、颜色分类
  • 二、排序数组
  • 三、数组中的第k个数
  • 四、最小的k个数
  • 总结

引言

本节主要介绍快速排序(三路划分,随机取key),以及它的变形算法——快速选择算法

一、颜色分类


细节:快速排序中标准的partition(三路划分)

  • 设置三个指针 left,cur,right
  • 划分为三个区域[0, left - 1],[left, right],[right + 1, n-1]
  • [0, left - 1]:元素小于key
  • [left, right]:元素等于key
  • [right + 1, n-1]:元素大于key
  • left和right用来维护(等于key的)中路元素区域的左右两端,cur用来扫描数组
class Solution
{
public:
    void sortColors(vector<int>& nums)
    {
        int left = 0, cur = 0, right = nums.size() - 1;
        while(cur <= right)
        {
            if(nums[cur] == 0) swap(nums[left++], nums[cur++]);
            else if(nums[cur] == 2) swap(nums[right--], nums[cur]);
            else ++cur;
        }
    }
};

二、排序数组


思路:

  • 递归出口:区间只有一个元素或者不存在
  • 随机选key:利用rand函数,记得提前srand种下随机数种子
  • 三路划分:三指针维护区间
  • 分治:继续递归[begin, left - 1],[right + 1, end]两个区间
class Solution
{
public:
    int getKey(vector<int>& nums, int left, int right)
    {
        int keyi = rand() % (right - left + 1) + left;
        return nums[keyi];
    }

    void quickSort(vector<int>& nums, int begin, int end)
    {
        if(begin >= end) return;

        int key = getKey(nums, begin, end);//随机选key

        int cur = begin, left = begin, right = end;
        while(cur <= right)
        {
            if(nums[cur] < key) swap(nums[left++], nums[cur++]);
            else if(nums[cur] > key) swap(nums[right--], nums[cur]);
            else cur++;
        }

        quickSort(nums, begin, left - 1);
        quickSort(nums, right + 1, end);
    }

    vector<int> sortArray(vector<int>& nums)
    {
        srand(0);//种下随机数种子
        quickSort(nums, 0, nums.size() - 1);
        return nums;
    }
};

三、数组中的第k个数


思路:TopK问题有三种解法

  1. 排序——O(NlogN)
  2. 堆——O(NlogK)
  3. 快速选择——O(N)

堆版本

细节:建大堆 + k-1次删除

class Solution
{
public:
    void AdjustDown(vector<int>& nums, int parent)
    {
        int n = nums.size(), child = 2 * parent + 1;
        while(child < n)
        {
            if(child + 1 < n && nums[child] < nums[child + 1]) ++child;

            if(nums[parent] < nums[child])//建大堆
            {
                swap(nums[parent], nums[child]);
                parent = child;
                child = 2 * parent + 1;
            }
            else break;
        }
    }

    int findKthLargest(vector<int>& nums, int k)
    {
        int n = nums.size();
        for(int i=(n-1-1)/2; i>=0; --i)
        {
            AdjustDown(nums, i);
        }

        while(--k)//执行k-1次
        {
            swap(nums[0], nums[nums.size() - 1]);
            nums.pop_back();
            AdjustDown(nums, 0);
        }
        return nums[0];
    }
};

快速选择版本

细节:

  • 从最右边开始数,k落在右区域,则继续递归找第k大
  • k落在中区域,则直接更新结果
  • k落在左区域,则继续递归找第k-b-c大
class Solution
{
    int ret;
public:
    int GetKey(vector<int>& nums, int begin, int end)
    {
        int keyi = rand() % (end - begin + 1) + begin;
        return nums[keyi];
    }

    void qucikSelect(vector<int>& nums, int begin, int end, int k)
    {
        if(begin > end) return;

        int key = GetKey(nums, begin, end);

        int left = begin, cur = begin, right = end;
        while(cur <= right)
        {
            if(nums[cur] < key) swap(nums[left++], nums[cur++]);
            else if(nums[cur] > key) swap(nums[right--], nums[cur]);
            else cur++;
        }

        if(k <= end - right) qucikSelect(nums, right + 1, end, k);
        else if(k <= end - left + 1) ret = key;
        else qucikSelect(nums, begin, left - 1, k - (end - left + 1));
    }

    int findKthLargest(vector<int>& nums, int k)
    {
        srand(0);
        qucikSelect(nums, 0, nums.size() - 1, k);
        return ret;
    }
};

四、最小的k个数



细节:

  • 从最左边开始数,k落在左区域,则继续递归找最小的k个元素
  • k落在中区域,则直接返回前k个元素
  • k落在右区域,则继续递归找最小的k-a-b个元素
class Solution
{
public:
    int getKey(vector<int>& nums, int begin, int end)
    {
        int keyi = rand() % (end - begin + 1) + begin;
        return nums[keyi];
    }

    void quickSelect(vector<int>& nums, int begin, int end, int k)
    {
        if(begin >= end) return;

        int key = getKey(nums, begin, end);

        int left = begin, cur = begin, right = end;
        while(cur <= right)
        {
            if(nums[cur] < key) swap(nums[left++], nums[cur++]);
            else if(nums[cur] > key) swap(nums[right--], nums[cur]);
            else cur++;
        }

        if(k <= left - begin) quickSelect(nums, begin, left - 1, k);
        else if(k <= right + 1 - begin) return;
        else quickSelect(nums, right + 1, end, k - (right + 1 - begin));
    }

    vector<int> inventoryManagement(vector<int>& nums, int k)
    {
        srand(0);
        quickSelect(nums, 0, nums.size() - 1, k);
        return {nums.begin(), nums.begin() + k};
    }
};

总结

快速排序,随机选key,保证了时间复杂度逼近O(NlogN),三路划分,是为了处理重复大量元素。

快速选择,是基于快速排序的变形算法,在解决TopK问题有着O(N)的时间复杂度,极其高效!


真诚点赞,手有余香

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

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

相关文章

类图的六大关系

类图中的六大关系包括&#xff1a;继承关系、实现关系、关联关系、聚合关系、组合关系和依赖关系。 1. 继承关系 继承是一种类与类之间的关系&#xff0c;表示一种泛化和特化的关系。子类继承父类的特性和行为。 class Animal {void eat() {System.out.println("This an…

足球走地全自动化操作软件实现过程

本次采用selenium实现自动化操作的流程 打开浏览器录入账号密码等待数据请求&#xff08;监听&#xff09;有新数据&#xff0c;进行自动化操作通过homeName搜索&#xff0c;找到对应数据找到对应的类型&#xff08;让、大小…&#xff09;找到对应的盘口输入数量提交 附登录…

系统资源监控器工具glances的使用详解

目录 1、glances工具介绍 2、安装方式 3、glances的工具界面说明 4、常用的参数选项 5、常用快捷键说明 1、glances工具介绍 glances可以分析系统的 CPU使用率、内存使用率、内核统计信息和运行队列信息磁盘I/O速度、传输和读/写比率、磁盘适配器网络I/O速度、传输和读/写…

华为编程题目(实时更新)

1.大小端整数 计算机中对整型数据的表示有两种方式&#xff1a;大端序和小端序&#xff0c;大端序的高位字节在低地址&#xff0c;小端序的高位字节在高地址。例如&#xff1a;对数字 65538&#xff0c;其4字节表示的大端序内容为00 01 00 02&#xff0c;小端序内容为02 00 01…

电脑远程控制另一台电脑怎么弄?

可以远程控制另一台电脑吗&#xff1f; “你好&#xff0c;我对远程访问技术不太了解。现在&#xff0c;我希望我的朋友可以远程控制我的Windows 10电脑&#xff0c;以便她能帮我解决一些问题。请问&#xff0c;有没有免费的方法可以实现这种远程控制&#xff1f;我该如何操作…

如何选择一个最强大模型-看最硬核排名了!

Chatbot Arena由伯克利大学主导团队 LMSYS Org 发布了一个针对大语言模型的基准平台 Chatbot Arena。该平台采用匿名、随机的方式让不同的大模型产品进行对抗评测&#xff0c;基于国际象棋等竞技游戏中广泛使用的埃洛等级分系统&#xff0c;通过用户投票产生&#xff0c;系统每…

基于SpringBoot的网盘系统设计与实现

第1章 绪论... 1 1.1 研究背景与意义... 1 1.1.1 研究背景... 1 1.1.1 研究意义... 1 1.2 国内外研究现状... 2 1.2.1 国内研究现状... 2 1.2.2 国外研究现状... 3 1.3 论文组织架构... 4 第2章 关键技术介绍... 5 2.1 SpringBoot. 5 2.2 MySQL数据库... 5 2.3 MVC架…

区块链论文总结速读--CCF A会议 USENIX Security 2024 共7篇 附pdf下载

Conference&#xff1a;33rd USENIX Security Symposium CCF level&#xff1a;CCF A Categories&#xff1a;网络与信息安全 Year&#xff1a;2024 Num&#xff1a;7 1 Title: Practical Security Analysis of Zero-Knowledge Proof Circuits 零知识证明电路的实用安全…

对AI 感兴趣的小伙伴

如图&#xff0c;欢迎来玩儿&#xff01; 欢迎来玩儿

备考AMC8和AMC10竞赛,吃透2000-2024年1850道真题和解析(持续)

多做真题&#xff0c;吃透真题和背后的知识点是备考AMC8、AMC10有效的方法之一&#xff0c;通过做真题&#xff0c;可以帮助孩子找到真实竞赛的感觉&#xff0c;而且更加贴近比赛的内容&#xff0c;可以通过真题查漏补缺&#xff0c;更有针对性的补齐知识的短板。 今天我们继续…

嵌入式学习——3——UDP TFTP简易文件传输

tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;已经不再支持 TFTP通信…

ping 探测网段哪些地址被用

#!/bin/bash# 遍历192.168.3.1到192.168.3.254 for i in {1..254} doip"192.168.3.$i"# 对每个IP地址进行三次ping操作if ping -c 3 -W 1 $ip > /dev/null 2>&1thenecho "$ip: yes"fi done$ sh test.sh 192.168.3.1: yes 192.168.3.95: yes 192.…

Terminal Web终端基础(Web IDE 技术探索 二)

Terminal是web终端技术&#xff0c;类似cmd命令窗口&#xff0c;Webcontainer 中推荐使用的是Xterm.js&#xff0c;这里就不细说Xterm.js 的使用了&#xff0c;我们使用第三方库来实现&#xff08;原生确实有点难用&#xff09;。 vue-web-terminal 一个由 Vue 构建的支持多内容…

基础5 探索JAVA图形编程桌面:字符操作组件详解

在繁华都市的一个角落&#xff0c;卧龙和凤雏相聚在他们常去的台球厅。灯光洒在绿色的台球桌上&#xff0c;彩色的台球整齐地排列着&#xff0c;仿佛在等待着一场激烈的角逐。 卧龙轻轻地拿起球杆&#xff0c;微微瞄准&#xff0c;然后用力一击&#xff0c;白球带着一股强大的力…

MySQL 高阶语句(二)

一、子查询 子查询也被称作内查询或者嵌套查询&#xff0c;是指在一个查询语句里面还嵌套着另一个查询语句。子查询语句是先于主查询语句被执行的&#xff0c;其结果作为外层的条件返回给主查询进行下一 步的查询过滤。PS: 子语句可以与主语句所查询的表相同&#xff0c;也可以…

Python异常处理:打造你的代码防弹衣!

Hi&#xff0c;我是阿佑&#xff0c;上文咱们讲到——揭秘Python的魔法&#xff1a;装饰器的超能力大揭秘 ‍♂️✨&#xff0c;阿佑将带领大家通过精准捕获异常、使用with语句和上下文管理器、以及异常链等高级技巧来增强代码的健壮性。就像为代码穿上防弹衣&#xff0c;保护它…

微调Llama3实现在线搜索引擎和RAG检索增强生成功能

视频中所出现的代码 Tavily SearchRAG 微调Llama3实现在线搜索引擎和RAG检索增强生成功能&#xff01;打造自己的perplexity和GPTs&#xff01;用PDF实现本地知识库_哔哩哔哩_bilibili 一.准备工作 1.安装环境 conda create --name unsloth_env python3.10 conda activate …

5.17 作业+思维导图+模拟面试

// tcp_ser.c #include <myheader.h>#define SER_PORT 8888 #define SER_IP "192.168.125.109"int newfd, sfd;int main(int argc, const char *argv[]) {//1、为通信创建一个端点sfd socket(AF_INET, SOCK_STREAM, 0);//参数1&#xff1a;说明使用的是ipv4通…

Elasticsearch不删原有jdk8导致的系列安装和启动问题

以前在空机器直接装elasticsearch&#xff0c;没有遇到什么问题。今天在现有JDK上安装&#xff0c;遇到的问题记录一下&#xff1a; 1. JDK的环境变量配置与我原有的不一致报如下错误&#xff1a; [estestZK-DES-I root]$ /usr/elasticsearch/bin/elasticsearch could not fi…