算法:分治思想处理快排递归以及快速选择/最小K个数问题

文章目录

  • 算法原理
  • 实现思路
  • 典型例题
    • 颜色分类
    • 快速排序优化
    • 数组中最大的K个数
    • 最小的K个数
  • 总结

算法原理

分治的原理就是分而治之,从原理上讲,就是把一个复杂的问题划分成子问题,再将子问题继续划分,直到可以解决

实现思路

基于分治的原理进行快速排序,区别于传统的快速排序,这里对快速排序进行改良,成为更优先的三路划分算法,可以处理一些极端场景,使快速排序的适用性更加广泛,同时引出快速选择算法,用来搭配堆排序解决topk问题

典型例题

颜色分类

在这里插入图片描述
本题和前面在双指针算法中做的移动0的解法类似,这里其实算法原理和快速排序优化的三路划分很相似,将数组中的区域划分为三个部分,分别为0,1,2,因此解决问题的时候要先想清楚如何解决,把数据量弄清楚

对于此题来说,算法思路就是如果遇到2,就把数据扔到最后,如果遇到0,就放到最前,那么1就会被天然的隔离到最中间的部分,这是可行的

快速排序优化

在这里插入图片描述

根据上面的原理,可以改进快速排序,快速排序的弊端在于,当他要进行处理很多相同数据的时候,就遇到十分低效的情况,基于这个原因,可以在实现它的过程中利用到一些上面的想法,这样的算法思路其实也叫做三路划分

因此可以使用这个方法来解题,否则会超时

class Solution 
{
public:
    vector<int> sortArray(vector<int>& nums) 
    {
        srand(time(0));
        quicksort(nums,0,nums.size()-1);
        return nums;
    }
    void quicksort(vector<int>& nums,int left,int right)
    {
        if(left>=right)
        {
            return;
        }
        int key=numsrandom(nums,left,right);
        int i=left,begin=left-1,end=right+1;
        while(i<end)
        {
            if(nums[i]<key)
            {
                swap(nums[++begin],nums[i++]);
            }
            else if(nums[i]==key)
            {
                i++;
            }
            else
            {
                swap(nums[--end],nums[i]);
            }
        }
        quicksort(nums,left,begin);
        quicksort(nums,end,right);
    }
    int numsrandom(vector<int>& nums,int left,int right)
    {
        int keyi=rand()%(right-left+1)+left;
        return nums[keyi];
    }
};

基于快速排序的三路划分原理,可以引申出新的思想:快速选择问题

数组中最大的K个数

在这里插入图片描述

看到这个题第一思想是使用堆排序,因为堆排序处理TopK问题是十分有效的,但是后面的限制条件,时间复杂度必须是O(N)的算法,因此这里并不能使用TopK算法

由于前面有快速排序的基础,因此这里可以引申出一个快速选择解法

首先看思路:

在快速排序的三路划分算法中,当划分结束后,整个数组会被天然的划分为下面三个部分:

在这里插入图片描述

假设,我们这里让蓝色区域的记作C,红色区域记作B,棕色区域记作A

那如果我们要求的这个第k个数据落在蓝色区域,那么我们只需要在C这个单位长度内寻找一次即可,如果落在红色区域,那么要找的这个数据就是key,如果落在棕色区域,则只需要在A这个单位长度寻找一次即可

由此,就引申出了快速选择算法:基于快速排序从而引申出的快速选择

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

    int quicksort(vector<int>& nums,int l,int r,int k)
    {
        if(l==r)
        {
            return nums[l];
        }

        // 1. 选取中间元素
        int key=getrandom(nums,l,r);
        int left=l-1,right=r+1,i=l;
        
        // 2. 三路划分
        while(i<right)
        {
            if(nums[i]<key)
            {
                swap(nums[++left],nums[i++]);
            }
            else if(nums[i]==key)
            {
                i++;
            }
            else
            {
                swap(nums[--right],nums[i]);
            }
        }

        // 3. 判断
        int c=r-right+1;
        int b=(right-1)-(left+1)+1;
        if(c>=k)
        {
            return quicksort(nums,right,r,k);
        }
        else if(b+c>=k)
        {
            return key;
        }
        else
        {
            return quicksort(nums,l,left,k-b-c);
        }
    }

    int getrandom(vector<int>& nums,int l,int r)
    {
        return nums[rand()%(r-l+1)+l];
    }
};

时间复杂度分析较为复杂,但是是严格符合题目要求的,由此其实也看出了分治的思想核心,把一个大问题转换成小问题,直到最后转换成一个我们一下就能解决的问题,不断的缩小我们需要寻找的区间,这样最终就能找到我们需要的答案

最小的K个数

在这里插入图片描述

class Solution 
{
public:
    vector<int> getLeastNumbers(vector<int>& nums, int k) 
    {
        srand(time(NULL));
        quicksort(nums,0,nums.size()-1,k);
        return {nums.begin(),nums.begin()+k};
    }

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

        // 1. 选基准元素
        int key=getrandom(nums,l,r);
        int left=l-1,right=r+1,i=l;
        
        // 2. 三路划分
        while(i<right)
        {
            if(nums[i]<key)
            {
                swap(nums[++left],nums[i++]);
            }
            else if(nums[i]==key)
            {
                i++;
            }
            else
            {
                swap(nums[--right],nums[i]);
            }
        }

        // 3. 快速选择
        int a=left-l+1,b=(right-1)-(left+1)+1;
        if(a>k)
        {
            quicksort(nums,l,left,k);
        }
        else if(a+b>=k)
        {
            return;
        }
        else
        {
            quicksort(nums,right,r,k-a-b);
        }
    }

    int getrandom(vector<int>& nums,int l,int r)
    {
        return nums[rand()%(r-l+1)+l];
    }
};

对于这个题来说,解法多种多样,可以采用很多方法,topk,直接排序,快速选择,这里依旧选择快速选择来写

原理和前面类似,由于返回的是前k个数不一定要有序,因此三路划分后可以直接进行条件判断,满足需求就可以跳出循环

总结

分治思想用以快速排序,可以引申出快速选择这个算法,而这个算法在实际应用中有很大的作用,对于解决前k个数或第k个数都有很大的算法意义,下篇会总结分治思想用以解决归并问题

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

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

相关文章

Qt使用Json

包含目录&#xff1a; #include <QJsonObject> #include <QJsonDocument> #include <QByteArray> #include <QFile> #include <QJsonArray>基本结构&#xff1a; 写json QJsonObject studentobj;QJsonArray arrarydata;QJsonObject subdata;…

CSS中如何实现元素的渐变背景(Gradient Background)效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS 渐变背景效果⭐ 线性渐变背景⭐ 径向渐变背景⭐ 添加到元素的样式⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

java内存模型讨论及案例分析

常用内存选项 -Xmx&#xff1a; 最大堆大小 -Xms&#xff1a;最小堆大小 -Xss &#xff1a;线程堆栈大小&#xff0c;默认1M 生产环境最好保持 Xms Xmx java内存研究 内存布局 可见&#xff1a; 堆大小 新生代 老年代&#xff0c;新生代EFrom SurvivorTo Survivor。新…

Flux语言 -- InfluxDB笔记二

1. 基础概念理解 1.1 语序和MySQL不一样&#xff0c;像净水一样通过管道一层层过滤 1.2 不同版本FluxDB的语法也不太一样 2. 基本表达式 import "array" s 10 * 3 // 浮点型只能与浮点型进行运算 s1 9.0 / 3.0 s2 10.0 % 3.0 // 等于 1 s3 10.0 ^ 3.0 // 等于…

C语言-内存分布(STM32内存分析)

C/C内存分布 一、内存组成二、静态区域文本段 &#xff08;Text / 只读区域 RO&#xff09;已初始化读写数据段&#xff08;RW data -- Initialized Data Segment&#xff09;未初始化数据段&#xff08;BSS -- Block Started by Symbol&#xff09; 三、动态区域堆&#xff08…

后端面试话术集锦第三篇:spring cloud 面试话术

这是后端面试集锦第三篇博文——spring cloud面试话术❗❗❗ 1. 什么是Springcloud Spring Cloud是一系列框架的集合,它利用Spring Boot的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。 他的设计目的是为了简化Spring应用的搭建和开发…

C++算法 —— 分治(2)归并

文章目录 1、排序数组2、数组中的逆序对3、计算右侧小于当前元素的个数4、翻转对 1、排序数组 排序数组 排序数组也可以用归并排序来做。 vector<int> tmp;//写成全局是因为如果在每一次小的排序中都创建一次&#xff0c;更消耗时间和空间&#xff0c;设置成全局的就更高…

强大的思维导图库SimpleMindMap

本文软件是网友 Frank Yang 推荐的&#xff1b; 什么是 SimpleMindMap &#xff1f; Simple Mind Map 是一个简单、强大的 Web 思维导图库&#xff0c;不依赖任何特定框架&#xff0c;可以帮助你快速开发思维导图产品。同时 Simple Mind Map 也是一个思维导图软件。无论你是开发…

13.动态渲染侧边栏

为什么要动态渲染&#xff1f; 比如我们现在需要以下侧边栏的数据&#xff1a; 如果一个个的去写标签会很麻烦&#xff0c;发现导航栏中的数据分为两类&#xff0c;一类是一级导航&#xff0c;另一位是二级导航&#xff08;有子页&#xff09;&#xff0c;因此直接写两个函数判…

MVC模式分层练习

新建库 新建表 插入点数据 先不用MVC模式写功能,来看下缺点是什么 新建一个空项目 选项项目使用的JDK 自己的IDEA总是要重启下 新建模块 因maven还没教 添加框架支持 添加后项目多了这些 添加些必要依赖 这里注意下,如果导入jar包不对可以重新导入下或者是jar包本身出了问…

中东 Shopify 如何使用 Bytebase 构建一站式数据库开发工作流

公司简介 Salla 是一家 2016 年成立&#xff0c;位于沙特麦加的自建站电商平台。 作为中东 Shopify&#xff0c;其最大的特点是支持阿拉伯语建站&#xff0c;并且提供更多适应中东地区特点的本地化服务。截止目前&#xff0c;已有 47,000 家店铺入驻 Salla&#xff0c;商品销售…

已解决‘jupyter‘ 不是内部或外部命令,也不是可运行的程序或批处理文件报错

本文摘要&#xff1a;本文已解决‘jupyter‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件的相关报错问题&#xff0c;并系统性地总结提出了几种可用解决方案。同时结合人工智能GPT排除可能得隐患及错误。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲…

C++--动态规划其他问题

1.一和零 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0…

ubuntu学习(六)----文件编程实现cp指令

1 思路 Linux要想复制一份文件通常指令为&#xff1a; cp src.c des.c 其中src.c为源文件&#xff0c;des.c为目标文件。 要想通过文件编程实现cp效果&#xff0c;思路如下 1 首先打开源文件 src.c 2 读src到buf 3 创建des.c 4 将buf写入到des.c 5 close两个文件 2 实现 vi …

容器技术Linux Namespaces和Cgroups

对操作系统了解多少&#xff0c;仅仅敲个命令吗 操作系统虚拟化&#xff08;容器技术&#xff09;的发展历程 1979 年&#xff0c;UNIX 的第 7 个版本引入了 Chroot 特性。Chroot 现在被认为是第一个操作系统虚拟化&#xff08;Operating system level virtualization&#x…

如何在 Vue TypeScript 项目使用 emits 事件

Vue是构建出色的Web应用程序的最灵活、灵活和强大的JavaScript框架之一。Vue中最重要的概念和关键特性之一是能够促进应用程序组件之间的通信。让我们深入探讨一下Vue中的“emits”概念&#xff0c;并了解它们如何以流畅和无缝的方式实现父子组件之间的通信。 Vue中的emits是什…

工控上位机程序为什么只能用C语言?

工控上位机程序并不只能用C#开发&#xff0c;实际上在工业自动化领域中&#xff0c;常见的上位机开发语言包括但不限于以下几种&#xff1a;C#: C#是一种常用的编程语言&#xff0c;在工控领域中被广泛使用。它具有良好的面向对象特性和丰富的类库支持&#xff0c;可以实现高性…

艾昆纬携手亚马逊云科技赋能生物医药企业,加速武田数字化转型

IQVIA艾昆纬是全球以及中国医疗健康服务领域的领导者&#xff0c;利用其数据及分析&#xff0c;前沿数字化技术和医疗领域的专业知识&#xff0c;智能连接医疗生态的各个环节。过去几年&#xff0c;IQVIA艾昆纬所服务的生物医药行业客户武田中国也迎来了数字化转型的高潮。 武田…

习题练习 C语言(暑期第三弹)

自我小提升&#xff01; 前言一、存储地址二、逗号表达式三、除自身以外数组的乘积四、字节与二进制五、符号计算六、不用加减乘除做加法七、unsigned判断八、移位计算九、sizeof宏十、移位计算十一、移位计算十二、优先级判断十三、单词倒排总结 前言 重要的事说三遍&#xf…

工厂方法模式的概述和使用

目录 一、工厂方法模式概述1. 定义2. 使用动机 二、工厂方法模式结构1. 模式结构2. 时序图 三、工厂方法模式的使用实例四、工厂方法模式的优缺点五、工厂方法模式在Java中应用 原文链接 一、工厂方法模式概述 1. 定义 工厂方法模式(Factory Method Pattern)又称为工厂模式&…