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

这篇具有很好参考价值的文章主要介绍了算法:分治思想处理快排递归以及快速选择/最小K个数问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

算法原理

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

实现思路

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

典型例题

颜色分类

算法:分治思想处理快排递归以及快速选择/最小K个数问题,C++,# 算法,习题集,算法
本题和前面在双指针算法中做的移动0的解法类似,这里其实算法原理和快速排序优化的三路划分很相似,将数组中的区域划分为三个部分,分别为0,1,2,因此解决问题的时候要先想清楚如何解决,把数据量弄清楚

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

快速排序优化

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

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

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

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个数

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

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

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

首先看思路:

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

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

假设,我们这里让蓝色区域的记作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个数

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

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个数都有很大的算法意义,下篇会总结分治思想用以解决归并问题文章来源地址https://www.toymoban.com/news/detail-690038.html

到了这里,关于算法:分治思想处理快排递归以及快速选择/最小K个数问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 快排算法(分治法)

            相信很多人接触到的第一个排序就是冒泡排序,冒泡排序是一种拿一个数依次和后面进行比较,这样也就确保了每一次排序之后不论降序还是升序这一个数都会在末尾或者最前端,那么今天我们要将的是快速排序,基于冒泡排序的改进版本,为什么说是改进呢。要

    2024年02月16日
    浏览(25)
  • 【算法】分治-快排

    个人主页 : zxctscl 如有转载请先通知 分治就是分而治之 就是把数组中的元素分为三块,0全部在左边,1全部在中间,2全部在右边。 这里要用到三个指针,一个i指针用来遍历,一个left用来存放0区域的最后侧,一个用来存放2区域的最左侧。 那么区间就分成了4个 只需要判断

    2024年04月25日
    浏览(18)
  • 【基础算法】八大排序算法:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序(快排),归并排序,计数排序

      🧑‍🎓 个人主页:简 料   🏆 所属专栏:C++   🏆 个人社区:越努力越幸运社区   🏆 简       介: 简料简料,简单有料~在校大学生一枚,专注C/C++/GO的干货分享,立志成为您的好帮手 ~ C/C++学习路线 (点击解锁) ❤️ C语言阶段(已结束) ❤️ 数据结构与算法(ing) ❤

    2024年02月01日
    浏览(31)
  • 插入,选择,堆,快速排序算法思想与复杂度

    目录 插入排序 思想 算法步骤 代码 复杂度 选择排序 思想 算法步骤 代码 复杂度 堆排序  思想 算法步骤 代码 复杂度  快速排序  思想 算法步骤 代码 复杂度 稳定性 插入排序是一种简单直观的排序算法。它的工作原理是将数组分为 已排序 和 未排序 两部分,然后依次将未

    2024年02月15日
    浏览(27)
  • 数据结构(C语言实现)——常见排序算法的基本思想及实现(快速排序的三种方法和优化及非递归实现快速排序)

    生活中几乎处处都会用到排序,比如:网购时的店铺顺序,学生成绩的排名等,今天我们就来学习数据结构中常见的几种排序算法。 排序 :所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性 :假定在待排序的记录序列

    2023年04月24日
    浏览(38)
  • 排序 | 冒泡 插入 希尔 选择 堆 快排 归并 非递归 计数 基数 排序

    排序算法是一种将一组数据按照特定顺序排列的算法。数据结构排序算法的选择取决于数据的特征、规模和性能需求。 接下来我们就要实现排序~~ 我们需要实现的一些功能: 冒泡排序是一种基本的排序算法,其核心思想是通过多次交换相邻元素的位置,使得每一轮循环都将

    2024年02月04日
    浏览(36)
  • 【排序算法】 归并排序详解!分治思想!

    🎥 屿小夏 : 个人主页 🔥个人专栏 : 算法—排序篇 🌄 莫道桑榆晚,为霞尚满天! ​ 什么是归并?通过归并排序就能让数据有序?分治法是怎么在归并排序上应用的?本文将对归并排序进行细致入微的讲解,庖丁解牛般让你彻底明白归并排序! 归并排序(MERGE-SORT)是建

    2024年02月08日
    浏览(33)
  • 全网最全的快速排序方法--Hoare快排 挖坑法快排 二路快排 三路快排 非递归快排

    目录 一.快速排序 1.基本介绍 2.基本思想 二.Hoare快排 0.前情知识 1.交换数组中的两个元素 2.指定范围的插入排序 1.基本思路 2.代码实现 3.优化思路 三.挖坑法快排(校招中适用) 1.基本思路 2.代码实现 四.二路快排 1.基本思路 2.代码实现 3.优化思路 五.三路快排 1.基本思路 2.代码

    2023年04月21日
    浏览(32)
  • 算法导论【分治思想】—大数乘法、矩阵相乘、残缺棋盘

    在分而治之的方法中,一个问题被划分为较小的问题,然后较小的问题被独立地解决,最后较小问题的解决方案被组合成一个大问题的解决。 通常,分治算法有三个部分: 分解:将问题划分为若干子问题,这些子问题是同一问题的较小实例。 解决:通过递归地解决子问题来

    2024年02月03日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包