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

目录

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

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

[【替代方案 1】使用快速选择](#【替代方案 1】使用快速选择)

[【替代方案 2】使用计数排序](#【替代方案 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 处的元素。

using System;

class GFG

{

static int kthSmallest(int\[\] arr, int k)

{

// Sort the given array

Array.Sort(arr);

// Return k'th element in the sorted array

return arrk - 1;

}

static void Main()

{

int\[\] arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};

int k = 4;

Console.WriteLine(kthSmallest(arr, k));

}

}

输出

5

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

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

using System;

class MaxHeap

{

private int\[\] heap;

private int size;

public MaxHeap(int capacity)

{

heap = new intcapacity;

size = 0;

}

public int Count => size;

public void Push(int val)

{

heapsize = val;

int i = size;

size++;

while (i > 0)

{

int parent = (i - 1) / 2;

if (heapparent >= heapi)

break;

int temp = heapparent;

heapparent = heapi;

heapi = temp;

i = parent;

}

}

public int Pop()

{

if (size == 0)

{

Console.WriteLine("Heap is empty");

return -1;

}

int top = heap0;

heap0 = heapsize - 1;

size--;

int i = 0;

while (true)

{

int left = 2 * i + 1;

int right = 2 * i + 2;

int largest = i;

if (left < size && heapleft > heaplargest)

largest = left;

if (right < size && heapright > heaplargest)

largest = right;

if (largest == i)

break;

int temp = heapi;

heapi = heaplargest;

heaplargest = temp;

i = largest;

}

return top;

}

public int Top()

{

if (size == 0)

{

Console.WriteLine("Heap is empty");

return -1;

}

return heap0;

}

}

class GFG {

static int kthSmallest(int\[\] arr, int k)

{

// Create a max heap

MaxHeap pq = new MaxHeap(arr.Length);

// Iterate through the array elements

for (int i = 0; i < arr.Length; i++)

{

// Push the current element onto the max heap

pq.Push(arri);

// If the size of the max heap exceeds k,

//remove the largest element

if (pq.Count > k)

pq.Pop();

}

// Return the kth smallest element (top of the max heap)

return pq.Top();

}

static void Main()

{

int\[\] arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};

int k = 4;

Console.WriteLine(kthSmallest(arr, k));

}

}

输出

5

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

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

using System;

class GFG {

static int partition(int\[\] arr, int left, int right) {

// Choose the last element as pivot

int pivot = arrright;

int i = left;

// Traverse the array and move elements <= pivot to the left

for (int j = left; j < right; j++) {

if (arrj <= pivot) {

// Swap current element with element at i

int temp = arri;

arri = arrj;

arrj = temp;

i++;

}

}

// Place the pivot in its correct position

int tempPivot = arri;

arri = arrright;

arrright = tempPivot;

return i;

}

static int quickSelect(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 arrpivotIndex;

else if (pivotIndex > k)

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

else

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

}

return -1;

}

static int kthSmallest(int\[\] arr, int k) {

return quickSelect(arr, 0, arr.Length - 1, k - 1);

}

static void Main() {

int\[\] arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};

int k = 4;

Console.WriteLine(kthSmallest(arr, k));

}

}

输出

5

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

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

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

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

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

using System;

class GFG {

static int kthSmallest(int\[\] arr, int k)

{

// First, find the maximum element in the array

int maxElement = arr0;

for (int i = 1; i < arr.Length; i++)

{

if (arri > maxElement)

maxElement = arri;

}

// Create a frequency array for each element

int\[\] freq = new intmaxElement + 1;

for (int i = 0; i < arr.Length; i++)

freqarr\[i]++;

// Keep track of cumulative frequency to find k-th smallest

int count = 0;

for (int i = 0; i <= maxElement; i++)

{

if (freqi != 0)

{

count += freqi;

if (count >= k)

{

// If we have seen k or more elements,

// return the current element

return i;

}

}

}

return -1;

}

static void Main()

{

int\[\] arr = {10, 5, 4, 3, 48, 6, 2, 33, 53, 10};

int k = 4;

Console.WriteLine(kthSmallest(arr, k));

}

}

输出

5

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

辅助空间: O(maxElement)。

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

相关推荐
2601_962218611 天前
万象生鲜系统业财一体化底层打通技术自动生成经营账单
大数据·数据库·人工智能·python·算法
吞下星星的少年·-·1 天前
The 2026 ICPC Asia East Continent Online Contest (II)(构造)
数据结构·算法
stolentime1 天前
洛谷P10515 转圈题解
c++·算法·数学建模·贪心算法
和裕1 天前
蜂窝板 vs 七层瓦楞重型纸箱:大件工业设备运输性能与成本全对比
大数据·运维·网络·人工智能·算法
衡石科技1 天前
Data_Agent记忆机制与经验复用衡石分析智能体会话记忆与长期学习技术解析
人工智能·科技·学习·算法·企业级bi
Msshu1231 天前
2~5串锂电快充优选|XSP36 Type‑C升压/升降压快充管理芯片
数据结构·随机森林·贪心算法·排序算法·线性回归·启发式算法
shirsl1 天前
算法 Day 2 滑动窗口 + 栈 / 单调栈
开发语言·python·算法
土司大王1 天前
LeetCode hot100 回溯专题总结:Java 通用模板、决策树模型
java·算法·leetcode·决策树
2601_962218611 天前
万象生鲜系统订单全生命周期状态同步技术实现业务可视
大数据·数据库·人工智能·python·算法