【算法】分治 - 快速排序



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的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)的时间复杂度,极其高效!


真诚点赞,手有余香

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习实验------Adaboost算法

第1关:什么是集成学习 任务描述 本关任务:根据本节课所学知识完成本关所设置的选择题。 第2关: Boosting 任务描述 本关任务:根据本节课所学知识完成本关所设置的选择题。 第3关:Adaboost算法流程 任务描述 本关任务:用Python实现Adaboost,并通过鸢尾花数据集…

聚观早报 | 华为畅享 70S真机图赏;vivo Y200 GT开售

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 5月25日消息 华为畅享 70S真机图赏 vivo Y200 GT开售 一加13部分细节曝光 马斯克谈AI未来 三星Galaxy Z Fold6将…

使用SDL_QT直接播放渲染YUV格式文件

0.前要 下载一个文件&#xff0c;名字为 400_300_25.mp4&#xff0c;我们用ffmplay.exe将其转化为yuv文件&#xff0c;具体操作如下&#xff1a; 进入cmd控制台&#xff0c;进入ffmplay.exe文件的目录下&#xff0c;输入ffmpeg -i 文件名.mp4 文件名.yuv 回车&#xff0c;会生…

每日练习之数学——砝码和天平

砝码和天平 题目描述 运行代码 #include<iostream> using namespace std; int main() {int w,m,T;cin>>T;while(T--){cin>>w>>m;while(m){if((m-1)%w0)m(m-1)/w;else if((m1)%w0)m(m1)/w;else if(m%w0)m/w;else break;}if(!m)cout<<"YES&…

检测头篇 | YOLOv8改进之添加小目标检测头 / 添加大目标检测头 / 减少检测头

前言:Hello大家好,我是小哥谈。本文首先给大家展示原始YOLOv8的网络结构图,然后再对其进行改变,即增加小目标检测头、增加大目标检测头和减少检测头。🌈 目录 🚀1.网络结构图

10.2.k8s的附加组件-Metrics-server组件与hpa资源pod水平伸缩

目录 一、概述 二、安装部署Metrics-Server组件 1.下载Metrics-Server资源清单 2.编辑Metrics-Server的资源清单 3.验证Metrics-Server是否成功安装 4.使用top命令测试是否管用 三、hpa资源实现pod水平伸缩&#xff08;自动扩缩容&#xff09; 1.编写deploy资源清单 2.…

什么是创造力?如何判断自己的创造力?

创造力&#xff0c;主要表现为创新思想、发现和创造新事物的能力&#xff0c;是知识&#xff0c;智力和能力的综合能力&#xff0c;尤其是在职业发展方面&#xff0c;创造力具有重要的意义&#xff0c;企业的核心竞争力就来源于创造力&#xff0c;这就需要具有创造力的员工来推…

HCIP-Datacom-ARST自选题库__OSPF单选【80道题】

1.OSPFV2是运行在IPV4网络的IGP&#xff0c;OSPFV3是运行在IPV6网络的ICP&#xff0c;OSPFV3与OSPFv2的报文类型相同&#xff0c;包括Hello报文、DD报文、LSR报文、LSU报文和LSAck报文。关于OSPFv3报文&#xff0c;以下哪个说法是正确的 OSPFv3使用报文头部的认证字段完成报文…

.DS_store文件

感觉mac里的这个.DS_store文件烦人&#xff0c;老是莫名其妙的出现&#xff0c;然后造成困扰 处理方式如下&#xff1a; import os pic_list os.listdir("./mask_pic/") print(len(pic_list)) # 从文件夹中删掉 if(".DS_Store" in pic_list):print(&quo…

如何关闭或者减少屏蔽 CloudFlare 的真人检测

经常浏览境外网站的应该常碰到一个真人检测的提示(如下图所示)。最近,明月就收到了一个知乎上的付费咨询:问我如何去掉这个提示,由此明月也特别的研究了一下这个“真人检测”,这算是 CloudFlare 的一个特色了,基本上大家看到站点访问有这个提示的几乎都是用了 CloudFlar…

亚马逊测评自养号需要解决哪些问题?

我们首先了解一下测评是什么 测评就是类似于国内某宝和某多补销量一样&#xff0c;可以快速提升产品销量和优质的评价&#xff0c;从而让产品的权重上升&#xff0c;可以上升产品排名 也可以防范同行的恶意差评&#xff0c;可以用好评稀释差评&#xff0c;从而控评&#xff0…

VSCODE gcc运行多个.c文件

一、简介 很多时候&#xff0c;开发者需要使用VSCODE进行C语言算法验证。而VSCODE的gcc编译&#xff0c;默认是只编译本文件的内容&#xff0c;其他.c文件是不参与编译的。这就给开发者带来很大的困扰&#xff0c;因为开发者不可能把所有的算法都写在一个.c文件&#xff0c;特别…

2024年5月计算机视觉论文推荐:包括扩散模型、视觉语言模型、图像编辑和生成、视频处理和生成以及图像识别等各个主题

我们今天总结下2024年5月发表的最重要的论文&#xff0c;重点介绍了计算机视觉领域的最新研究和进展&#xff0c;包括扩散模型、视觉语言模型、图像编辑和生成、视频处理和生成以及图像识别等各个主题。 Diffusion Models 1、Dual3D: Efficient and Consistent Text-to-3D Ge…

mac清理软件推荐免费 mac清理系统数据怎么清理 cleanmymac和腾讯柠檬哪个好

macbook是苹果公司的一款高性能的笔记本电脑&#xff0c;受到了很多用户的喜爱。但是&#xff0c;随着使用时间的增长&#xff0c;macbook的系统也会积累一些垃圾文件&#xff0c;影响其运行速度和空间。那么&#xff0c;macbook系统清理软件推荐有哪些呢&#xff1f;macbook用…

模板编译之入口分析

Vue 是一个渐进式 JavaScript 框架&#xff0c;提供了简单易用的模板语法&#xff0c;帮助开发者以声明式的方式构建用户界面。Vue 的模板编译原理是其核心之一&#xff0c;它将模板字符串编译成渲染函数&#xff0c;并在运行时高效地更新 DOM。本文将深入探讨 Vue 模板编译的原…

Optica数据库 (原OSA美国光学学会电子期刊)文献去哪里查找下载

Optica&#xff08;OSA&#xff09;数据库涵盖了光学和光子学理论研究和实际应用的各个领域&#xff0c;包括&#xff1a;光学设备、光学成像、光纤通信、分析方法、光通信、光纤、半导体激光、光传输、光学系统、计量学、带宽、量子电子学。 该库包括18种学会期刊&#xff08…

5月21日 网络编程day4

1.项目中如何实现TCP的并发&#xff1f; 答&#xff1a;采用多进程、多线程或者IO多路复用进行通信。 2.TCP通信过程中的三次握手&#xff1f; 答&#xff1a;①&#xff1a;客户端发送SYN包&#xff08;SYN1&#xff0c;seq0&#xff09;给服务器&#xff0c;并进入SYN_SEN…

【大模型】 基于AI和全球化进程的权衡:开源大模型与闭源大模型

【大模型】 基于AI和全球化进程的权衡&#xff1a;开源大模型与闭源大模型 前言 实际上关于开源or闭源&#xff0c;一直以来都是颇有争议的话题&#xff0c;人们争执于数据的隐私性和共享性&#xff0c;到底哪一方能获得的收益更大。而对于开源与闭源哪个更好实际上也就是说是…

YoloV9实战与改进——专栏目录

摘要 &#x1f525;&#x1f680;本专栏教你如何嗨翻Yolov9&#xff01;&#x1f680;&#x1f525; &#x1f680;炸裂升级&#xff1a;嗨&#xff0c;小伙伴们&#xff01;这里有一波Yolov9的升级大招&#xff0c;带你领略最新论文的精华&#xff01;&#x1f4a5; 什么注意…

ue引擎游戏开发笔记(47)——设置状态机解决跳跃问题

1.问题分析&#xff1a; 目前当角色起跳时&#xff0c;只是简单的上下移动&#xff0c;空中仍然保持行走动作&#xff0c;并没有设置跳跃动作&#xff0c;因此&#xff0c;给角色设置新的跳跃动作&#xff0c;并优化新的动作动画。 2.操作实现&#xff1a; 1.实现跳跃不复杂&…