最快效率求出乱序数组中第k小的数

Posted xiaoyh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最快效率求出乱序数组中第k小的数相关的知识,希望对你有一定的参考价值。

题目:以尽量高的效率求出一个乱序数组中按数值顺序的第k 的元素值

思路:这里很容易想到直接排序然后顺序查找,可以使用效率较高的快排,但是它的时间复杂度是O(nlgn),我们这里可以用一种简便的方法,不一定需要排序,使用快速排序中双向分区的扫描方法,扫描出主元下标,然后根据主元的值将数组划分成一半大,一半小。然后再根据主元下标与k进行比较,如果相等,说明主元就是我们要找的数,如果大于k,说明k所代表的值在小的那边,继续向小的那部分递归,如果小于k,说明k代表的值在大的那边,继续向大的那部分递归。这样即可得出正确答案。这种方法的时间复杂度为O(n),因为每次递归都相当于舍弃掉了差不多一半的数。

代码:

import java.util.Arrays;

public class SelectK {

    public static void main(String[] args) {
        
        int arr[] = new int[10];
        for(int i=0;i<10;i++){
            arr[i] = (int) ((Math.random()+1)*10);
        }
        
        System.out.println("查找前数组:"+Arrays.toString(arr));
        int k = selectK(arr, 0, arr.length-1, 5);
        System.out.println("查找出第k小的元素:"+k);

    }
    
    /**
     * 
     * @param arr
     * @param p 开始下标
     * @param r    结束下标
     * @param k 求第k小元素  (递增第k个元素)
     * @return
     */
    public static int selectK(int[] arr,int p,int r,int k){
        int q = partition2(arr, p, r);  // 主元的下标
        int qk = q - p + 1;   // 主元是第几个元素
        if (qk==k) {
            return arr[q];
        }else if (qk>k) {
            return selectK(arr, p, q-1, k);
        }else {
            return selectK(arr, q+1, r, k-qk);
        }
        
        
    }
    //双向扫描分区法
    public static int partition2(int[] arr, int p, int r) {
        int left = p + 1; //左侧扫描指针
        int right = r; //右侧指针
        int pivot = arr[p];
        while(left <= right) {
            // left不停往右走,直到遇到大于主元的元素
            // 循环退出时,left一定是指向第一个大于主元的位置
            while(left <= right && arr[left] <= pivot) {
                left++;
            }
            // right不停往左走,直到遇到小于主元的元素
            // 循环退出时,right一定是指向从右到左第一个小于于主元的位置
            while(left <= right && arr[right] > pivot) {
                right--;
            }
            if(left < right)
                swap(arr, left, right);
        }
        // 循环退出时,两者交错,且right指向的最后一个小于等于主元的位置,也就是主元应该待的位置
        swap(arr, p, right);
        return right;
    }
    
    private static void swap(int[] A, int p, int bigger) {
        int temp = A[p];
        A[p] = A[bigger];
        A[bigger] = temp;
        
    }
}

结果:

  技术分享图片

 

以上是关于最快效率求出乱序数组中第k小的数的主要内容,如果未能解决你的问题,请参考以下文章

2020-03-02:在无序数组中,如何求第K小的数?

选择问题(选择数组中第K小的数)

找轮转后的有序数组中第K小的数

9.27 在两个排序数组中找到第K小的数

LeetCode 668. 乘法表中第k小的数 / 462. 最少移动次数使数组元素相等 II / 436. 寻找右区间

选择N个数据中第K小的数据输出