news 2026/8/25 16:42:15

C++ 第k个最小元素(K’th Smallest Element)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 第k个最小元素(K’th Smallest Element)

目录

【朴素方法】使用排序——时间复杂度为 O(n log(n)),空间复杂度为 O(1)

【预期方法】使用最大堆 - 时间复杂度为 O(n * log(k)),空间复杂度为 O(k)

【替代方案 1】使用快速选择

【替代方案 2】使用计数排序


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

给定一个整数数组arr[]和元素个数k,求数组中第 k 小的元素。
注意:k 始终小于数组的大小。

例如:

输入:arr[] = [10, 5, 4, 3, 48, 6, 2, 33, 53, 10], k = 4

输出:5

说明:给定数组中第四小的元素是 5。

输入:arr[] = [7, 10, 4, 3, 20, 15], k = 3

输出:7

说明:给定数组中第三小的元素是 7。

【朴素方法】使用排序——时间复杂度为 O(n log(n)),空间复杂度为 O(1)

其思路是对给定的数组进行排序,并返回索引 k - 1 处的元素。

#include<iostream>
#include <algorithm>
#include<vector>

using namespace std;

int kthSmallest(vector<int>& arr, int k)
{
// Sort the given vector
sort(arr.begin(), arr.end());

// Return k'th element in the sorted vector
return arr[k - 1];
}

int main()
{
vector<int> arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};
int k = 4;

cout << kthSmallest(arr, k);
return 0;
}

输出
5

【预期方法】使用最大堆 - 时间复杂度为 O(n * log(k)),空间复杂度为 O(k)

其思路是在遍历数组的过程中维护一个大小为 k 的最大堆。该堆始终包含目前为止遇到的 k 个最小元素。如果堆的大小超过 k,则移除最大的元素。最终,堆中只保留 k 个最小元素。

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int kthSmallest(vector<int>& arr, int k) {

// Create a max heap
priority_queue<int> pq;

// Iterate through the array elements
for (int i = 0; i < arr.size(); i++)
{
// Push the current element onto the max heap
pq.push(arr[i]);

// If the size of the max heap exceeds k,
//remove the largest element
if (pq.size() > k)
pq.pop();
}

return pq.top();
}

int main()
{
vector<int> arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};
int k = 4;

cout << kthSmallest(arr, k);
}

输出
5

【替代方案 1】使用快速选择

主要思路是利用快速选择(QuickSelect)函数找到第 k 大元素。具体做法是:选择一个基准元素,然后将数组分割成多个部分,使得大于基准元素的元素位于左侧,小于基准元素的元素位于右侧。如果基准元素最终位于索引 k-1 处,则该元素即为第 k 大元素。否则,我们递归地仅在包含第 k 大元素的左侧或右侧部分进行搜索。

#include <iostream>
#include <vector>
using namespace std;

int partition(vector<int>& arr, int left, int right) {

// Choose the last element as pivot
int pivot = arr[right];
int i = left;

// Traverse the array and move elements <= pivot to the left
for(int j = left; j < right; j++) {
if(arr[j] <= pivot) {

// Swap current element with element at i
swap(arr[i], arr[j]);
i++;
}
}

// Place the pivot in its correct position
swap(arr[i], arr[right]);
return i;
}

// QuickSelect function: recursively finds k-th smallest
int quickSelect(vector<int>& arr, int left, int right, int k) {

if(left <= right) {

// Partition around pivot
int pivotIndex = partition(arr, left, right);

// Found k-th smallest
if(pivotIndex == k) return arr[pivotIndex];

else if(pivotIndex > k)
return quickSelect(arr, left, pivotIndex - 1, k);

else return quickSelect(arr, pivotIndex + 1, right, k);
}
return -1;
}

int kthSmallest(vector<int>& arr, int k) {
return quickSelect(arr, 0, arr.size()-1, k-1);
}

int main() {
vector<int> arr = {10,5,4,3,48,6,2,33,53,10};
int k = 4;
cout << kthSmallest(arr, k);
}

输出
5

时间复杂度: 最坏情况下为O(n² ),但平均时间为 O(n log n),且性能优于基于优先级队列的算法。

辅助空间: 最坏情况下递归调用栈为 O(n)。平均而言:O(log n)。

【替代方案 2】使用计数排序

主要思路是利用计数排序的频率计数来跟踪有多少元素小于或等于每个值,然后直接从这些累积计数中识别出第 K 小的元素,而无需对数组进行完全排序。

注意:这种方法在元素范围较小时特别有效,因为我们声明的数组大小为最大元素个数。如果元素范围非常大,计数排序方法可能并非最有效的选择。

#include <iostream>
#include <vector>

using namespace std;

int kthSmallest(vector<int>& arr, int k) {

// First, find the maximum element in the vector
int maxElement = arr[0];
for (int i = 1; i < arr.size(); i++)
{
if (arr[i] > maxElement)
{
maxElement = arr[i];
}
}

// Create an array to store the frequency of each element
vector<int> freq(maxElement + 1, 0);
for (int i = 0; i < arr.size(); i++)
{
freq[arr[i]]++;
}

// Keep track of the cumulative frequency of elements
int count = 0;
for (int i = 0; i <= maxElement; i++)
{
if (freq[i] != 0)
{
count += freq[i];
if (count >= k)
{
// If we have seen k or more elements,
// return the current element
return i;
}
}
}
return -1;
}

int main()
{
vector<int> arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};
int k = 4;
cout << kthSmallest(arr, k);
return 0;
}

输出
5

时间复杂度: O(n + maxElement),其中 maxElement 为数组中的最大元素。

辅助空间: O(maxElement)。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/25 16:38:13

宝塔面板实战指南:从零搭建服务器运维图形化管理平台

1. 项目概述&#xff1a;为什么我们需要宝塔面板&#xff1f;如果你刚接触服务器运维&#xff0c;或者是一名开发者&#xff0c;面对黑漆漆的命令行终端&#xff0c;要手动安装Nginx、MySQL、PHP&#xff0c;再配置防火墙、SSL证书&#xff0c;是不是感觉头大如斗&#xff1f;我…

作者头像 李华
网站建设 2026/8/25 16:36:11

基于QtPy (PySide6) 的PLC-HMI工程实战记录(二)复制和应用PLC模板

一、复制前面做好的PLC项目模板&#xff0c;另存为新的项目并打开1、按照PLC的实际硬件进行完整组态2、编写变量表二、根据变量表&#xff0c;确定需要发送给上位机的数据范围本项目是一个小系统&#xff0c;为了简化设计&#xff0c;PLC的上行数据使用了固定周期发送&#xff…

作者头像 李华
网站建设 2026/8/25 16:27:06

斯坦福EE364B凸优化II课程:从次梯度方法到模型预测控制的实践指南

这次我们来看一个来自斯坦福大学的经典课程资源——EE364B凸优化II。这门课程在2008年由Stephen Boyd教授讲授&#xff0c;内容涵盖了从次梯度方法到模型预测控制等高级主题。对于从事优化理论、控制系统、机器学习等领域的研究人员和工程师来说&#xff0c;这是一份极具价值的…

作者头像 李华
网站建设 2026/8/25 16:20:55

ASP项目实战:从环境搭建到功能测试的完整指南

这次我们来看一个名为“赛博多娜”的项目&#xff0c;它不是一个AI模型&#xff0c;而是一个用ASP技术实现的、带有“家具装修”主题的Web应用开发周报。从标题和有限的材料来看&#xff0c;这是一个技术分享或项目进度记录&#xff0c;核心是展示如何使用ASP&#xff08;Activ…

作者头像 李华
网站建设 2026/8/25 16:20:50

ASP动态界面开发:游戏化拖拽布局与数据持久化实战

最近在开发一个基于ASP的Web应用项目时&#xff0c;遇到了一个有趣的需求&#xff1a;如何将游戏化的“装修”概念融入后台管理界面&#xff0c;以提升用户&#xff08;特别是内部运营人员&#xff09;的交互体验。这让我联想到一些模拟经营游戏&#xff0c;比如“赛博多娜”这…

作者头像 李华
网站建设 2026/8/25 16:16:36

实力加冕!广州合优网络斩获 2022 年度网易外贸通市场开拓先锋奖

1. 引言 2022 年度网易外贸通合作伙伴大会圆满落幕。在这场汇聚行业精英的盛会上&#xff0c;广州合优网络科技有限公司凭借在外贸数字化服务领域的卓越表现与强劲的市场拓展能力&#xff0c;从众多优秀服务商中脱颖而出&#xff0c;一举斩获**「2022 年度网易外贸通市场开拓先…

作者头像 李华