跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

快速选择算法实战:求解数组第 K 大元素与最小 K 个数

快速选择算法通过分区策略优化了传统排序过程,专门用于解决数组中第 K 大元素及最小 K 个数问题。该方法利用三路划分将数组分为大于、等于、小于基准值的三个区间,根据区间长度递归定位目标,平均时间复杂度逼近 O(N)。相比全排序 O(NlogN) 和堆排序 O(NlogK),在处理大规模数据时效率更高,适合面试及工程实践中的 Top-K 场景。

RedisGeek发布于 2026/3/28更新于 2026/7/1939 浏览
快速选择算法实战:求解数组第 K 大元素与最小 K 个数

在处理'第 K 大'或'最小 K 个数'这类问题时,全排序往往效率不高。这里介绍一种基于快速排序思想优化的快速选择算法(Quick Select),平均时间复杂度可降至 O(N)。

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

题目描述

给定整数数组 nums 和整数 k,请返回该数组中第 k 个最大的元素。

注意你需要找的是排序后第 k 大的元素,而不是第 k 个不同的元素。

解法思路

核心在于利用快速排序的分区(Partition)逻辑。在快排中,我们将数组分为三块:大于基准值、等于基准值、小于基准值。通过计算每个区间的长度,我们可以直接判断目标元素落在哪个区间,从而避免对另一侧进行递归处理。

对于第 K 大元素,我们关注的是右侧(较大值)区域的元素数量。如果右侧区域元素个数 >= k,说明目标在右边;如果在中间区域,则当前基准值即为答案;否则在左边,且需要调整 k 的值。

代码实现

class Solution {
public:
    int Top_k(vector<int>& nums, int left, int right, int k) {
        if (left == right) {
            return nums[left];
        }
        // 三路划分:[left, l] [l+1, r-1] [r, right]
        int l = left - 1, r = right + 1, i = left;
        // 随机选择基准元素,避免最坏情况
        int key = nums[rand() % (right - left + 1) + left];
        
        while (i < r) {
            if (nums[i] > key) {
                swap(nums[i], nums[--r]);
            } else if (nums[i] < key) {
                swap(nums[i++], nums[++l]);
            } else {
                i++;
            }
        }
        
        // 若右边区域元素个数>=k,说明第 k 大的数在右边区域
        if (right - r + 1 >= k) {
            return Top_k(nums, r, right, k);
        }
        // 若右边区域个数<k,但中间加右边区域个数>=k,说明第 k 大的数在中间区域
        else if (right - l >= k) {
            return key;
        }
        // 若中间加右边区域个数<k,说明第 k 大的数在左边区域
        else {
            return Top_k(nums, left, l, k - (right - l));
        }
    }

    int findKthLargest(vector<int>& nums, int k) {
        srand(time(NULL));
        return Top_k(nums, 0, nums.size() - 1, k);
    }
};

流程解析

算法执行时,首先随机选取一个基准值,将数组划分为大于、等于、小于三部分。随后根据各部分的大小关系,决定是继续向右递归、向左递归还是直接返回基准值。这种剪枝策略使得我们不需要对整个数组排序即可找到目标。

46. 最小的 K 个数

题目描述

输入整数数组 stock 和整数 cnt,请返回数组中最小的 cnt 个数。

解法思路

这道题与上一题逻辑高度相似,同样采用快速选择的分区策略。不同之处在于,我们需要保留左侧较小的 cnt 个数。当分区完成后,如果左侧区域(小于基准值的区域)大小已经满足 cnt,则无需再处理右侧;如果不足,则需要在右侧继续寻找剩余数量的元素。

相比堆排序(O(NlogK))和全排序(O(NlogN)),快速选择算法的平均时间复杂度接近 O(N),在处理大规模数据时优势明显。

代码实现

class Solution {
public:
    vector<int> inventoryManagement(vector<int>& stock, int cnt) {
        if (cnt == 0) {
            return {};
        }
        srand(time(NULL));
        Top_k(stock, 0, stock.size() - 1, cnt);
        return vector<int>(stock.begin(), stock.begin() + cnt);
    }

    void Top_k(vector<int>& nums, int left, int right, int cnt) {
        if (left == right) {
            return;
        }
        int key = nums[rand() % (right - left + 1) + left];
        int l = left - 1, r = right + 1, i = left;
        
        while (i < r) {
            if (nums[i] > key) {
                swap(nums[i], nums[--r]);
            } else if (nums[i] < key) {
                swap(nums[i++], nums[++l]);
            } else {
                i++;
            }
        }
        
        // 左侧区域元素个数 >= cnt,说明最小的 k 个数都在左侧
        if (l - left + 1 >= cnt) {
            return Top_k(nums, left, l, cnt);
        }
        // 左侧区域不足,但左侧加中间区域足够,说明基准值及其左侧已包含所有结果
        else if (r - left >= cnt) {
            return;
        }
        // 需要在右侧继续寻找
        else {
            return Top_k(nums, r, right, cnt - (r - left));
        }
    }
};

流程解析

通过同样的三路划分逻辑,我们不断缩小搜索范围。当左侧累积的元素数量达到 cnt 时,数组的前 cnt 个位置即为所求的最小值集合。这种方法避免了不必要的排序开销,是解决此类 Top-K 问题的经典方案。

目录

  1. 45. 数组中的第 K 个最大元素
  2. 题目描述
  3. 解法思路
  4. 代码实现
  5. 流程解析
  6. 46. 最小的 K 个数
  7. 题目描述
  8. 解法思路
  9. 代码实现
  10. 流程解析
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Java 智能仿真无人机项目 V4 版本实战
  • C++ STL 进阶:unordered_set 与 unordered_map 用法及底层模拟
  • 本地 Ubuntu 服务器部署 OpenClaw 完整教程
  • SpringBoot 自动配置机制:从原理到实践的深度解析
  • OpenClaw AI 代理首日体验:代码生成与数据爬取实战
  • 使用腾讯云 HAI 和 DeepSeek 搭建响应式个人网页
  • 医疗送药机器人三重链式编程技术解析:空间拓扑、动态决策与容错控制
  • Spring Boot 4.0 虚拟线程时代:WebFlux 与 WebMVC 选型指南
  • FPGA 电源系统设计及器件选型指南
  • Python 3.12.0 Windows 环境安装与配置指南
  • 基于 DeepSeek 与腾讯云 HAI 快速构建个人主页
  • 客观审视开源平台 BuildingAI
  • 鸿蒙金融理财全栈:风控、合规与产品实现
  • 二分查找实战:旋转数组最小值与缺失数字查找
  • C++ 入门:引用、内联函数与 C++11 新特性详解
  • GraphicsPath 与 GDI+ 矩阵变换 Transform 实战
  • LLM 提示词工程核心原理与实战技巧
  • Spark DataFusion Comet 向量化:Rust Native ScanExec 与 Selection Vectors
  • JavaScript 中 var、let、const 的核心区别与实战应用
  • 二级 Python 考试真题及参考代码合集(基本操作题)

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online