📌  相关文章
📜  小范围未排序数组中的第k个最小最大(1)

📅  最后修改于: 2023-12-03 14:53:56.464000             🧑  作者: Mango

小范围未排序数组中的第k个最小最大

在程序开发中,我们常常需要查找数组中第k小或第k大的元素,当数组比较大时,一般使用快排等排序算法,但是当数组比较小或者需要多次查找时,使用排序算法反而不如直接查找效率高。本文将介绍一种时间复杂度为O(n)的算法,即小范围未排序数组中的第k个最小最大。

问题描述

给定一个长度为n的未排序数组,以及一个整数k,找到该数组中第k小的元素和第k大的元素。

解决方案

该问题可以分别解决第k小和第k大的问题,下面以第k小为例。

算法流程
  1. 随机选择一个元素pivot,将数组中小于pivot的元素放入左子数组,大于pivot的元素放入右子数组。
  2. 计算左子数组中元素的个数count,根据count与k的大小关系判断第k小的元素在左子数组还是右子数组中。
  3. 递归查找左/右子数组中第k小的元素。(如果count等于k,当前pivot即为第k小的元素)
代码实现
int findKthSmallest(int arr[], int n, int k)
{
    if (n <= 0) {
        return -1; // 数组为空
    }
    int pivotIndex = rand() % n;
    int pivot = arr[pivotIndex];
    int leftCount = 0;
    int* leftArr = new int[n];
    int* rightArr = new int[n];
    for (int i = 0; i < n; i++) {
        if (i == pivotIndex) continue;
        if (arr[i] < pivot) {
            leftArr[leftCount++] = arr[i];
        } else {
            rightArr[i-leftCount-1] = arr[i];
        }
    }
    if (leftCount+1 == k) {
        return pivot;
    } else if (leftCount+1 > k) {
        return findKthSmallest(leftArr, leftCount, k);
    } else {
        return findKthSmallest(rightArr, n-leftCount-1, k-leftCount-1);
    }
}
时间复杂度

由于每次递归时数组大小减半,故时间复杂度为O(n)。

注意事项
  1. 由于本算法可产生递归深度达到n的情况(每次pivot都取到最大或最小值),故需注意栈溢出问题。
  2. 若需同时查找第k小和第k大的元素,则需先排序(例如使用插入排序,时间复杂度为O(nk)),再查找。
总结

小范围未排序数组中的第k个最小最大问题是算法面试经常考察的问题,掌握该算法可提高程序开发效率和通过面试的概率。