给定一个不同整数的数组和一个整数,其中 小于数组大小,任务是找到数组中第 k 个最小的元素。
示例:

请注意,解决这个问题的方法有多种,详见《未排序数组中的k个最小/最大元素》。这里讨论的解决方案在实践中效果最佳。
其理念是使用随机枢轴选择来划分数组,通过聚焦子数组(第k个元素必须所在)来减少搜索空间。
一步步的方法:
选择随机枢轴:随机选择一个元素作为枢轴。这有助于避免某些情况下的最坏情况(比如数组已经排序)。
划分:重新排列数组,使所有小于枢轴的元素位于左侧,大于枢轴的元素在右侧。
递归搜索:一旦枢轴定位,如果其索引等于 n 的比较,则它是第 K 大元素。如果没有,则递归搜索相应的划分(左或右),其中 n。
// Java program to find K'th Smallest/
// Largest Element in Unsorted Array
import java.util.Random;
class GfG {
// Partition function: Rearranges elements
// around a pivot (last element)
static int partition(int[] arr, int l, int r) {
int x = arr[r];
int i = l;
// Iterate through the subarray
for (int j = l; j <= r - 1; j++) {
// Move elements <= pivot to the left partition
if (arr[j] <= x) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
}
}
// Place the pivot in its correct position
int temp = arr[i];
arr[i] = arr[r];
arr[r] = temp;
return i;
}
// Randomizes the pivot to avoid worst-case performance
static int randomPartition(int[] arr, int l, int r) {
Random rand = new Random();
int n = r - l + 1;
int pivot = rand.nextInt(n);
int temp = arr[l + pivot];
arr[l + pivot] = arr[r];
arr[r] = temp;
return partition(arr, l, r);
}
// function to find the k'th smallest element using QuickSelect
static int quickSelect(int[] arr, int l, int r, int k) {
// Check if k is within the valid range of
// the current subarray
if (k > 0 && k <= r - l + 1) {
// Partition the array and get the
// pivot's final position
int pos = randomPartition(arr, l, r);
// If pivot is the k'th element, return it
if (pos - l == k - 1)
return arr[pos];
// If pivot's position is larger than k,
// search left subarray
if (pos - l > k - 1)
return quickSelect(arr, l, pos - 1, k);
// Otherwise, search right subarray and adjust k
// (k is reduced by the size of the left partition)
return quickSelect(arr, pos + 1, r, k - (pos - l + 1));
}
// Return infinity for invalid k (error handling)
return Integer.MAX_VALUE;
}
static int kthSmallest(int[] arr, int k) {
int n = arr.length;
return quickSelect(arr, 0, n - 1, k);
}
public static void main(String[] args) {
int[] arr = {12, 3, 5, 7, 4, 19, 26};
int k = 3;
System.out.println(kthSmallest(arr, k));
}
}
输出
5
时间复杂度:O(n) 上述解的最坏情况下时间复杂度仍为 O(n2)。在最坏情况下,随机函数可能总是选择一个角元素。然而,平均情况下的时间复杂度为 。分析假设随机数生成器生成输入范围内任意数字的可能性相等。
辅助空间: 自使用常数变量以来,O(1)。O(n)
即使最坏时间复杂度是二次方,这种解在实际中也表现最佳。
编程资源
https://pan.quark.cn/s/7f7c83756948
更多资源
https://pan.quark.cn/s/bda57957c548