优选算法的妙思之流:分治——快排专题

news2025/4/5 22:01:51

专栏:算法的魔法世界

个人主页:手握风云

目录

一、快速排序

二、例题讲解

2.1. 颜色分类

2.2. 排序数组

2.3. 数组中的第K个最大元素

2.4. 库存管理 III


一、快速排序

        分治,简单理解为“分而治之”,将一个大问题划分为若干个子问题,直到这个子问题能够快速解决。我们之前的快速排序是选出一个数作为基准值,然后将一个数组划分为两个子序列,一个序列<=基准值,另一个>基准值。但这种算法在数据特别大的时候是会超时的。所以我们这里要使用更优秀的三块划分和随机选择基准元素的算法。

二、例题讲解

2.1. 颜色分类

        这道题我们可以参照移动零里面的划分策略。移动零里面是利用双指针将数组分为0区域和非0区域,这道题我们也可以使用三个指针left、right、i来将其划分为0、1、2区域。其中i用来遍历数组,left用来标记0区域的最右侧,right用来标记2区域的最左侧。

        接下来进行分类讨论:如果nums[i]=0,我们让nums[left+1]与nums[i]进行交换,然后i++,left++,就能保证[left+1,i-1]区间还都是1,还可能有一种极端情况,就是i=left+1,自身与自身进行交换,还是得需要left和i++,综上我们就可以写成nums[++left]与nums[i++]进行交换。如果nums[i]=1,我们直接就可以i++就可以。如果nums[i]=2时,right的移动也可以参照上面left的处理,--right,但i不能++,因为i右侧是未遍历的区间,如果i++,就会跳过这个元素。当i=right时,结束循环。

        完整代码实现:

class Solution {
    public void sortColors(int[] nums) {
        int left = -1, right = nums.length, i = 0;

        while (i < right) {
            if (nums[i] == 0)
                swap(nums, ++left, i++);
            else if (nums[i] == 1)
                i++;
            else if (nums[i] == 2)
                swap(nums, --right, i);
        }
    }

    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

2.2. 排序数组

        这道题如果我们直接采用之前的快排思想是会超时的,因为如果数组里的元素都等于基准值key,这样数组元素就会跑到数组的最右侧,导致时间复杂度会退化成O(n^{2})

        我们接下来利用数组分三块的思想,将其划分为3个区域,<=key,=key,>=key。这样当基准值都等于key时,时间复杂度直接降为O(n)

        接下来就是如何随机选择基准值。我们需要在数组下标中等概率地选择一个下标,那么我们就可以利用随机数种子,利用公式r%(right-left+1)+left求出随机下标。

        完整代码实现:

class Solution {
    public int[] sortArray(int[] nums) {
        Quicksort(nums, 0, nums.length - 1);
        return nums;
    }

    private void Quicksort(int[] nums, int l, int r) {
        if (l >= r) return;//作为递归结束的条件

        //数组分三块
        int key = nums[new Random().nextInt(r - l + 1) + l];
        int left = l - 1, right = r + 1, i = l;
        while (i < right) {
            if (nums[i] < key) swap(nums, ++left, i++);
            else if (nums[i] == key) i++;
            else if (nums[i] > key) swap(nums, --right, i);
        }
        Quicksort(nums, l, left);
        Quicksort(nums, right, r);
    }

    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

2.3. 数组中的第K个最大元素

        因为这道题让我们用时间复杂度为O(n),所以我们的思路很明显要使用快速选择排序,也就是上一题的数组分三块与随机选择基准元素。那么这个第K大的元素就有可能落在三个区域内,我们设三个区域的元素个数分别为a、b、c。如果c>=k,那我们就直接去>key的这个区域去寻找;如果b+c>=k,就直接返回key;如果前两个都不成立,就去<key这个区间去寻找第k-b-c大的元素。

        完整代码实现:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        return Quicksort(nums, 0, nums.length - 1, k);
    }

    private int Quicksort(int[] nums, int l, int r, int k) {
        if (l == r) return nums[l];

        //随机选择基准元素
        int key = nums[new Random().nextInt(r - l + 1) + l];

        //根据基准元素,把数组分为三块
        int left = l - 1, right = r + 1, i = l;
        while (i < right) {
            if (nums[i] < key) swap(nums, ++left, i++);
            else if (nums[i] == key) i++;
            else if (nums[i] > key) swap(nums, --right, i);
        }

        //分类讨论
        //区间:[l,left],[left+1,right-1],[right,r]
        int b = right - left - 1, c = r - right + 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);
    }

    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

2.4. 库存管理 III

        题目就是求数组中的最小的cnt个数。第一种解法,可以使用Arrays.sort()方法来对数组进行排序,找出前k个元素;第二种解法,利用大根堆,创建一个大小为k的大根堆,将数组的前k个元素丢进大根堆中,然后再将数组剩余的元素与堆顶元素比较,如果小就交换并调整堆,最后堆里面就是最小的k个数;第三个解法,就是快速选择算法。第一种解法的时间复杂度为NlogN,第二种解法的时间复杂度为Nlog(cnt),第三中解法的时间复杂度为N

        按照上一题的思路,将数组分为三块,三个区间内元素的个数分别为a、b、c。如果a>cnt,那么我们只需要去<key的区间去寻找;如果a+b>=cnt,此时的cnt一定是大于a的,那么最小的cnt个数,一定位于左侧两个区间,而中间区间又都是等于key的,所以不需要递归,直接++;如果前两个都不成立,直接去最右侧的区间去寻找第cnt-a-b个元素。

        完整代码实现:

class Solution {
    public int[] inventoryManagement(int[] stock, int cnt) {
        Quicksort(stock,0,stock.length - 1,cnt);
        int[] ret = new int[cnt];
        for (int i = 0; i < cnt; i++) {
            ret[i] = stock[i];
        }
        return ret;
    }

    private void Quicksort(int[] nums, int l, int r, int k) {
        if(l >= r) return;

        //随机获取基准元素
        int key = nums[new Random().nextInt(r - l + 1) + l];
        int left = l - 1,right = r + 1,i = l;

        //数组分三块
        while(i < right){
            if(nums[i] < key) swap(nums,++left,i++);
            else if (nums[i] == key) i++;
            else if (nums[i] > key) swap(nums,--right,i);
        }

        //分类讨论
        int a = left - l + 1,b = right - left - 1;
        if(a > k) Quicksort(nums,l,left,k);
        else if (a + b >= k) return;
        else Quicksort(nums,right,r,k - a - b);
    }

    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

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

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

相关文章

wx206基于ssm+vue+uniapp的优购电商小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

React编程高级主题:错误处理(Error Handling)

文章目录 **5.2 错误处理&#xff08;Error Handling&#xff09;概述****5.2.1 onErrorReturn / onErrorResume&#xff08;错误回退&#xff09;****1. onErrorReturn&#xff1a;提供默认值****2. onErrorResume&#xff1a;切换备用数据流** **5.2.2 retry / retryWhen&…

ubuntu20.04升级成ubuntu22.04

命令行 sudo do-release-upgrade 我是按提示输入y确认操作&#xff0c;也可以遇到配置文件冲突时建议选择N保留当前配置

SpringCloud(25)——Stream介绍

1.场景描述 当我们的分布式系统建设到一定程度了&#xff0c;或者服务间是通过异步请求来通讯的&#xff0c;那么我们避免不了使用MQ来解决问题。 假如公司内部进行了业务合并或者整合&#xff0c;需要服务A和服务B通过MQ的方式进行消息传递&#xff0c;而服务A用的是RabbitMQ&…

centos8上实现lvs集群负载均衡dr模式

1.前言 个人备忘笔记&#xff0c;欢迎探讨。 centos8上实现lvs集群负载均衡nat模式 centos8上实现lvs集群负载均衡dr模式 之前写过一篇lvs-nat模式。实验起来相对顺利。dr模式最大特点是响应报文不经调度器&#xff0c;而是直接返回客户机。 dr模式分同网段和不同网段。同…

uniapp如何接入星火大模型

写在前面&#xff1a;最近的ai是真的火啊&#xff0c;琢磨了一下&#xff0c;弄个uniappx的版本开发个东西玩一下&#xff0c;想了想不知道放啥内容&#xff0c;突然觉得deepseek可以接入&#xff0c;好家伙&#xff0c;一对接以后发现这是个付费的玩意&#xff0c;我穷&#x…

MySQL vs MSSQL 对比

在企业数据库管理系统中&#xff0c;MySQL 和 Microsoft SQL Server&#xff08;MSSQL&#xff09;是最受欢迎的两大选择。MySQL 是一款开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由 MySQL AB 开发&#xff0c;现归属于 Oracle 公司。而 MSSQL 是微…

python基础-10-组织文件

文章目录 【README】【10】组织文件&#xff08;复制移动删除重命名&#xff09;【10.1】shutil模块(shell工具)【10.1.1】复制文件和文件夹【10.1.1.1】复制文件夹及其下文件-shutil.copytree 【10.1.2】文件和文件夹的移动与重命名【10.1.3】永久删除文件和文件夹【10.1.4】用…

ORA-09925 No space left on device 问题处理全过程记录

本篇文章关键字&#xff1a;linux、oracle、审计、ORA-09925 一、故障现像 朋友找到我说是他们备份软件上报错。 问题比较明显&#xff0c;ORA-09925&#xff0c;看起来就是空间不足导致的 二、问题分析过程 这里说一下逐步的分析思路&#xff0c;有个意外提前说一下就是我…

多输入多输出 | Matlab实现BO-GRU贝叶斯优化门控循环单元多输入多输出预测

多输入多输出 | Matlab实现BO-GRU贝叶斯优化门控循环单元多输入多输出预测 目录 多输入多输出 | Matlab实现BO-GRU贝叶斯优化门控循环单元多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现BO-GRU贝叶斯优化门控循环单元多输入多输出预测&#…

27信号和槽_自定义信号(2)

自定义信号和槽 绑定信号和槽 如何才能触发出自定义的信号呢?&#xff08;上诉代码只是将信号和槽绑定在一起&#xff0c;但并没有触发信号&#xff09; Qt 内置的信号,都不需要咱们手动通过代码来触发 用户在 GUI, 进行某些操作,就会自动触发对应信号.(发射信号的代码已经内置…

人工智能在生物医药领域的应用地图:AIBC2025将于6月在上海召开!

人工智能在生物医药领域的应用地图&#xff1a;AIBC2025将于6月在上海召开&#xff01; 近年来&#xff0c;人工智能在生物医药行业中的应用受到广泛关注。 2024年10月&#xff0c;2024诺贝尔化学奖被授予“计算蛋白质设计和蛋白质结构预测”&#xff0c;这为行业从业人员带来…

2025.3.19

1、用vim编辑/etc/hosts文件&#xff0c;将本机和第二个虚拟机的ip地址和主机名写入该文件&#xff0c;然后ping 两个主机的主机名能否ping通&#xff1b; &#xff08;1&#xff09;在第一个虚拟机编辑/etc/hosts: 首先使用hostname、hostnamectl、hostname -f指令查看主机名…

深度学习 Deep Learning 第16章 结构化概率模型

深度学习 Deep Learning 第16章 结构化概率模型 内容概要 本章深入探讨了结构化概率模型&#xff08;Graphical Models&#xff0c;包含有向图和无向图模型&#xff09;的概念及其在深度学习中的应用。结构化概率模型通过图结构描述随机变量之间的直接交互&#xff0c;从而简…

鸿蒙 harmonyOS 网络请求

应用通过HTTP发起一个数据请求&#xff0c;支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。 接口说明 HTTP数据请求功能主要由http模块提供。 使用该功能需要申请ohos.permission.INTERNET权限。 第一步 &#xff1a; 在module.json5文件里面添加网络…

进程概念(Linux)

目录 一. 冯诺依曼体系结构 二. 操作系统(OS(操作系统的英文缩写Operator System)) 2.1概念 2-2 设计OS的目的 2.3 核心功能 2.4 如何管理&#xff08;先描述再组织&#xff09; 2.5 系统调用和库函数概念 三.进程 3.1 基本概念与基本操作 3.2 描述进程-PCB 3.3 如何…

免费在线MBTI性格测试工具 - 探索你的性格特质

免费在线MBTI性格测试工具 - 探索你的性格特质 简介 我很高兴为大家分享这个专业的MBTI性格测试工具。这是一个完全免费的在线测试系统&#xff0c;基于迈尔斯-布里格斯类型指标(MBTI)理论开发&#xff0c;旨在帮助您更好地了解自己的性格特征&#xff0c;发现职业发展方向。…

AI 数理逻辑基础之统计学基本原理(上)

目录 文章目录 目录统计学统计学基本概念描述性统计数据可视化图表工具 汇总统计统计数据的分布情况&#xff1a;中位数、众数、平均值统计数据的离散程度&#xff1a;极差、方差、标准差、离散系数 相关分析Pearson 线性关系相关系数Spearman 单调关系相关系数 回归分析回归模…

积分赛——读取实时时间

设计要求 调用DS1302芯片驱动程序&#xff0c;读取DS1302中的实时时分秒数据&#xff0c;并显示在数码管上。 23时59分59秒 通过串口发送时间作为定时时间&#xff0c;定时时间到则蜂鸣器响2s后静音。 串口发送格式&#xff1a;“12&#xff1a;35&#xff1a;66”。 备注&…

进程和线程的概念及Linux操作

文章目录 一、进程与线程1、进程2、线程3、查看进程与线程 二、Linux的“虚拟内存管理”&#xff0c;它与stm32中的 真实物理内存&#xff08;内存映射&#xff09;有什么区别&#xff1f;三、Linux系统调用函数 fork()、wait()、exec() 等1、fork&#xff08;&#xff09;函数…