当前位置: 首页 > news >正文

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)。

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

http://www.cnnetsun.cn/news/4213246.html

相关文章:

  • 宝塔面板实战指南:从零搭建服务器运维图形化管理平台
  • 基于QtPy (PySide6) 的PLC-HMI工程实战记录(二)复制和应用PLC模板
  • 斯坦福EE364B凸优化II课程:从次梯度方法到模型预测控制的实践指南
  • ASP项目实战:从环境搭建到功能测试的完整指南
  • ASP动态界面开发:游戏化拖拽布局与数据持久化实战
  • 实力加冕!广州合优网络斩获 2022 年度网易外贸通市场开拓先锋奖
  • 故障注入测试(FIT)在汽车控制器开发中的专业实践:从ISO 26262到HIL工程落地
  • 导师反复要求补图?用AI把毕业设计逻辑整理成清晰结构
  • 健身预约类毕业设计:内容匹配+协同过滤的混合推荐怎么设计权重
  • Go GOMAXPROCS:cgroup与CPU配额管理
  • 从 MyContext 看 AI 办公 Agent 的上下文基建(local-first / 知识图谱 / 冲突处理)
  • 从 RAP 服务到 Business Role,彻底理解 SAP BTP ABAP environment 里的 IAM Application
  • webrtc-rs/webrtc v0.20.3更新:Android 网络切换后 ICE Restart 卡死约 10 秒的问题终于解决
  • (十四)IP-MAC 绑定配置命令五厂商对照:华为 华三 锐捷 迈普 思科
  • 2026年7月泰安市新房价格深度分析报告
  • 测试时间优化与多站点并行测试
  • 读取DB块全报错?西门子优化的块访问与PUT/GET权限配置全解
  • PaddleOCR从入门到进阶:OCR技术学习路线与核心算法解析
  • 第五篇:结构化输出——让 AI 返回类型安全的 Java 对象
  • 响应式网格系统——从 Mobile-first 到 Ultra-wide 的适配工程
  • STM32专题之内部FLASH详解
  • php生成html代码 PHP一键生成HTML,服务器CPU狂降90%,这招太狠了
  • Google能索引,AI却抓不到
  • SDD 规范驱动实战:我用 Vibe Coding 开发了一个 AI 网页翻译 Chrome 插件
  • 2026年7月黄石市新房价格深度分析报告
  • 面向具身智能的TVA-VLA长程任务记忆与技能复用
  • php json schema 你的PHP JSON Schema验证,真能像健身库一样,一个git clone就搞定吗?
  • [通信与计算]通信原理03:信道容量与信道编码:原理与工程实践
  • js实践小案例
  • 无偏教师 v2:适用于无锚框和基于锚框检测器的半监督目标检测