C++算法 —— 分治(1)快排

news2024/11/20 6:24:07

文章目录

  • 1、颜色分类
  • 2、排序数组
  • 3、第k个最大的元素(快速选择)
  • 4、最小的k个数(快速选择)


分治,就是分而治之,把大问题划分成多个小问题,小问题再划分成更小的问题。像快排和归并排序就是分治思想。分治需要把数据分成几个区间,分区间则要通过基准值来划分

1、颜色分类

颜色分类

在这里插入图片描述

其实这道题的做法是三指针。双指针思路中,定义两个指针,假设要把整个数组划分成a和b区间,ab区间的数有各自的特点,一个指针遍历整个数组,另一个指针指向a区间的最后一个元素位置。而三指针,也是同样的思路,三个指针,abc三个区间,一个指针仍然在遍历数组,但它不需要遍历完所有,一个指针指向a区间的最右侧,一个指针指向c区间的最左侧,这样三个区间也就能划分出来了。在实际操作中,会分出四个区间

在这里插入图片描述

[0, left]全是0,[left + 1, i - 1]全是1,[i, right - 1]是待扫描的元素,[right, n - 1]全是2。

代码开始时,我们要如何做?left和right自然是在整个数组下标的0和n - 1处,i每次检测到数字,就去判断应该放到哪个区间,然后交换元素,把数字放到区间,left或者right移动,而i如果是放到left左边,i可以++,但是和right右边的元素交换后,i不能++,它还需要判断交换过来的数字。

    void sortColors(vector<int>& nums) {
        int n = nums.size();
        int i = 0, left = -1, right = n;//为什么要这么设置left和right1的值? 看下面的代码就能明白了
        while(i < right)//为什么要小于right?right到最后都是为2的元素,等到i和right重合时,其实就已经完成了整体的排序
        {
            if(nums[i] == 0)
            {
                swap(nums[++left], nums[i++]);
            }
            else if(nums[i] == 1)
            {
                i++;
            }
            else if(nums[i] == 2)
            {
                swap(nums[--right], nums[i]);
            }
        }
    }

2、排序数组

排序数组

在这里插入图片描述

其实这道题就是实现快排。我们要设置基准值key,把区间划分成两部分,<=key 和 >key,然后再到两个区间实现同样的操作,找key,划分区间。如果数组里都是重复元素的话,这个排序的复杂度就不好了。那么这里就把数组分三块的思想来实现快排,其实这个数组分三块的思路就是排序(2)那篇博客中的双指针法,思路都相似。我们要分成三个区间,< key = key > key,每次比较的时候就是交换,指针++等操作。

同上面一样

小于key:swap(nums[++left], nums[i++])
等于key:i++
大于key:swap(nus[–right], nums[i])

但是这里还有优化,上面时间复杂度是O(N),想要达成N * logN,就必须要随机选取key值。而这里的随机也不是简单的随机,我们要让整个区间的数都能等概率地没取到,我们的做法就是rand() % (right - left + 1) + left,偏移量 + left得到对应的数值,这个得出来的值是数组的下标,也就是nums[rand() % (right - left + 1) + left]。

上代码

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

    void qsort(vector<int>& nums, int l, int r)
    {
        if(l >= r) return ;
        //数组分三块
        int key = getRandom(nums, l, r);
        int i = l, left = l - 1, right = r + 1;//这里就和上面的颜色分类的做法就一样了,也就是上面灰框中的实现
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]);
        }
        qsort(nums, l, left);
        qsort(nums, right, r);
    }

    int getRandom(vector<int>& nums, int left, int right)
    {
        int r = rand();
        return nums[r % (right - left + 1) + left];
    }

3、第k个最大的元素(快速选择)

数组中的第K个最大元素

在这里插入图片描述

TOP K有4种问题,第k大,第k小,前k大,前k小。之前的博客对此用的是堆排序的算法。还有另外一个就是快速选择算法。堆排是O(N*logN),而快速选择是O(N)。

快速选择基于快排。整个区间左右端点为l和r,分成三个区间abc,三个区间内,我们需要确定第k大的数字在哪个区间内。假设abc就是每个区间的元素个数,如果在第三个区间,也就是>key的区间,那么c >=k;如果第一个条件不成立,那么如果在第二区间,那么b + c >=k,直接返回key就行,因为第二个区间都是=key的数字;如果上面两个条件都不成立,那么就去第一个区间找,找k - (b + c)大的数字。

    int findKthLargest(vector<int>& nums, int k) {
        /*priority_queue<int, vector<int>, greater<int>> pq(nums.begin(), nums.begin() + k);
        for(size_t i = k; i < nums.size(); ++i)
        {
            if(nums[i] > pq.top())
            {
                pq.pop();
                pq.push(nums[i]);
            }
        }
        return pq.top();*/
        //上面是用优先级队列解决的
        srand(time(NULL));
        return qsort(nums, 0, nums.size() - 1, k);
    }

    int qsort(vector<int>& nums, int l, int r, int k)
    {
        if(l == r) return nums[l];//必然存在至少一个元素,所以l不可能大于r
        //1. 随机选择基准元素
        int key = getRandom(nums, l, r);
        //2. 根据基准元素分三块
        int left = l - 1, right = r + 1, i = l;
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]);
        }
        int c = r - right + 1;
        int b = right - left - 1;
        if(c >= k) return qsort(nums, right, r, k);
        else if(b + c >= k) return key;
        else return qsort(nums, l, left, k - b - c);
    }

    int getRandom(vector<int>& nums, int left, int right)
    {
        return [rand() % (right - left + 1) + left];
    }

4、最小的k个数(快速选择)

剑指 Offer 40. 最小的k个数

在这里插入图片描述

针对这样的问题,我们可以堆排序,也可以快速选择算法。堆排是N * logk,快速选择可以到达N。

还是l ,left, right, r,abc。如果a > k,那就在a区间找;条件不符合,那就去a + b >= k,那就返回key,因为第一个条件不符合,那么第二个条件符合的话,k一定就是在=key的区间,那就返回key;上述两种条件都不符合,那就得在c区间找。

对上一个稍作修改。

   vector<int> getLeastNumbers(vector<int>& arr, int k) {
        srand(time(NULL));
        qsort(arr, 0, arr.size() - 1, k);
        return {arr.begin(), arr.begin() + k};
    }


    void qsort(vector<int>& nums, int l, int r, int k)
    {
        if(l == r) return ;
        int key = getRandom(nums, l, r);
        int left = l - 1, right = r + 1, i = l;
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]);
        }
        int a = left - l + 1;
        int b = right - left - 1;
        if(a > k) return qsort(nums, l, left, k);
        else if(b + a >= k) return ;
        else qsort(nums, right, r, k - b - a);
    }

    int getRandom(vector<int>& nums, int left, int right)
    {
        return nums[rand() % (right - left + 1) + left];
    }

结束。

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

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

相关文章

Linux网络编程 网络基础知识

目录 1.网络的历史和协议的分成 2.网络互联促成了TCP/IP协议的产生 3.网络的体系结构 4.TCP/IP协议族体系 5.网络各层的协议解释 6.网络的封包和拆包 7.网络预备知识 1.网络的历史和协议的分成 Internet-"冷战"的产物 1957年十月和十一月&#xff0c;前苏…

centOS下载与安装

1 下载centOS镜像 The CentOS Project 选择阿里云的镜像 2 下载虚拟机 Vmware workstation VMware - Delivering a Digital Foundation For Businesses 1 下载安装 centOs是一个操作系统&#xff0c;操作硬件的。所以需要有机器&#xff0c;可以使用虚拟机。 2 创建新的虚…

org.mockito:mockito-core 组件安全漏洞及健康度分析

组件简介 维护者mockito组织许可证类型MIT首次发布2008 年 4 月 29 日最新发布时间2023 年 8 月 27 日GitHub Star14159GitHub Fork2478依赖包24,748依赖存储库145,258 org.mockito:mockito-core是一个流行的 Java 模拟框架&#xff0c;它提供了一个简洁的 API 来创建和使用模拟…

【笔记】常用 js 函数

数组去重 Array.from(new Set()) 对象合并 Object.assign . 这里有个细节&#xff1a;当两个对象中含有key相同value不同时&#xff0c;会以 后面对象的key&#xff1a;value为准 保留小数点后几位 toFixed 注意&#xff1a; Number型&#xff0c;用该方法处理完&#xff0c;会…

Windows右键添加用 VSCODE 打开

1.安装VSCODE时 安装时会有个选项来添加&#xff0c;如下&#xff1a; ①将“通过code 打开“操作添加到windows资源管理器文件上下文菜单 ②将“通过code 打开”操作添加到windows资源管理器目录上下文菜单 说明&#xff1a;①②勾选上&#xff0c;可以对文件&#xff0c;目…

O2OA(翱途)开发平台 V8.1正式发布

尊敬的O2OA(翱途)平台合作伙伴、用户以及亲爱的开发小伙伴们&#xff0c;平台 V8.1版本已正式发布。正值8月的最后一周&#xff0c;我们以更安全、更高效、更好用的崭新面貌迎接9月的到来。 O2OA开发平台v8.1版本更注重于对系统级别的安全防护。其中重大的更新&#xff0c;是对…

Re44:数据集 GSM8K 和 论文 Training Verifiers to Solve Math Word Problems

诸神缄默不语-个人CSDN博文目录 论文全名&#xff1a;Training Verifiers to Solve Math Word Problems GSM8K数据集原始论文 OpenAI 2021年的工作&#xff0c;关注解决MWP问题&#xff08;具体场景是小学&#xff08;grade school&#xff09;数学题&#xff09;&#xff0c…

Java设计模式:四、行为型模式-09:模板模式

文章目录 一、定义&#xff1a;模板模式二、模拟场景&#xff1a;模板模式三、改善代码&#xff1a;模板模式3.0 引入依赖3.1 工程结构3.2 模板模式结构图3.3 爬取商品生成海报实现3.3.1 HTTP获取连接类3.3.2 定义执行顺序的抽象类3.3.3 当当爬取抽象实现类3.3.4 京东爬取抽象实…

java八股文面试[多线程]——synchronized锁升级详细流程

偏向锁 偏向锁是JDK6中的重要引进&#xff0c;因为HotSpot作者经过研究实践发现&#xff0c;在大多数情况下&#xff0c;锁不仅不存在多线程竞争&#xff0c;而且总是由同一线程多次获得&#xff0c;为了让线程获得锁的代价更低&#xff0c;引进了偏向锁。 偏向锁是在单线程执…

python3.11教程1:python基础语法、程序控制、函数

文章目录 一、Python简介1.1 为什么学习python1.2 python安装与配置1.3 python解释器1.4 命令行参数1.4.1 sys.argv变量1.4.2 -c和-m选项 1.5 解释器的运行环境1.5.1 编码格式1.5.2 编码声明 二、Python基础语法2.1 行结构2.2 变量&#xff08;标识符&#xff09;2.3 字节串2.4…

如何让照片动起来?几步操作轻松动起来

现在&#xff0c;许多人都喜欢在社交媒体上分享自己的照片。但是&#xff0c;有时单张静态照片可能无法完全表达出你想要表达的感觉。为了使你的照片更生动有趣&#xff0c;你可以使用一些简单的技巧使它们动起来。下面是几个简单的步骤。 步骤1&#xff1a;打开制作应用并导入…

图像融合去雾、近红外去雾、(近)红外和可见光数据集

今天给大家分享一篇发表在IEEE TMM上的去雾文章Joint Contrast Enhancement and Exposure Fusion for Real-World Image Dehazing 作者从对比度增强和曝光融合的视角来解决图像去雾问题&#xff0c;在真实场景上取得了较好的去雾效果。此外&#xff0c;作者将所提出的方法应用…

Json解析流程

一、拿到了题库 分析一下可以定义的 1、序号&#xff0c;用来区分题目数&#xff0c;每个题有唯一的序号 2、题目&#xff0c;就是下图的Q 3、预设的回答&#xff0c;下图的A 分析完我可以知道有三个字段&#xff0c;分别是int index、string Q、string A。 二、把字段丢到…

MongoDB 会丢数据吗? 在次补刀MongoDB 双机热备

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis &#xff0c;Oracle ,Oceanbase 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加微信号 liuaustin3 &#xff08;…

git 查看当前分支最近一次提交的commit SHA

获取当前分支最近一次commit SHA &#xff08;长度为40个16进制数字的字符&#xff09;命令如下&#xff1a; git rev-parse HEAD 获取简写&#xff08;短&#xff09; commit SHA git rev-parse --short HEAD

灾备中的网络加密是什么?

什么是网络加密&#xff1f; 在网络设计之初&#xff0c;对网络安全的问题考虑的不周全&#xff0c;数据在链路上传输的时候都是明文传输的&#xff0c;稍微有点技术的人&#xff0c;都可以轻松的拿到网络上的数据流量&#xff0c;并进行查看。试想一下&#xff0c;如果我们为…

Revit SDK 介绍:DistanceToPanels 根据距离设置参数

前言 这个例子展示如何计算距离&#xff0c;并将距离的值设置为参数。 内容 选中球形&#xff0c;运行程序&#xff0c;会设置控制高度的参数&#xff0c;距离越远参数值越大。效果如下所示&#xff1a; 核心逻辑&#xff1a; 得到选中物体的位置遍历分割表面内部的 Panel…

DAY07_Maven高级——分模块开发与设计依赖管理聚合与继承属性管理多环境配置与应用私服

目录 一 分模块开发与设计1. 分模块开发的意义问题导入模块拆分原则 2. 分模块开发问题导入2.1 创建Maven模块2.2 书写模块代码2.3 通过maven指令安装模块到本地仓库&#xff08;install指令&#xff09; 二 依赖管理1. 依赖传递问题导入 2. 可选依赖问题导入 3. 排除依赖问题导…

HVV行动之态势感知平台(一)

知攻善防&#xff0c;遇强则强&#xff01; 先介绍一下什么是HVV行动&#xff1a; 它是由公安部牵头的&#xff0c;通过组织红队和蓝队进行为期两周到三周的攻防对抗演习&#xff0c;来检测一些企业单位可能存在的网络漏洞和威胁&#xff0c;进而进行修复和加固&#xff0c;提…

go web之一:hello world快速上手+handle(http.Handle和http.HandleFunc的区别与联系)

前情提要&#xff1a; 需要安装好go的环境和VSCode的go插件。 hello world快速上手 1、创建go.mod 在项目根目录下打开命令行&#xff0c;或者直接用VSCode中的终端。输入命令 go mod init github.com/solenovex/web-tutorial 然后就能看到项目结构中多了一个go.mod 2、…