题解 | #寻找第K大#

寻找第K大

https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf

思路

对于本题来说,最简单粗暴的方法就是,使用一个平均复杂度为O(nlogn )的排序算法(归并或者堆排等等...)直接将数组元素排序,返回第K大的元素就行了

但是我们也可以利用快速排序,将快速排序改造一下降低时间复杂度

快速排序的核心思想就是划分,确定一个基准值(为了方便取数组排序上界的值),在左边且大于该基准值的元素移动到右边,在右边且小于该基准值的元素移动到左边

设排序下界为start,排序上界为end,那么:

  • 当end-start +1 == K时,说明当前索引所在的值为第K大的元素(end-start = K-1,当前索引右边有K-1个大于当前值的元素)
  • 当end-start +1 > K时,说明当前索引所在位置在K值的左边,直接向右快排(左边就不用继续快排了)
  • 当end-start +1< K时,说明当前索引所在位置在K值的右边,向左快排,注意此时我们式子end - pivot + 1的值为大于K的元素的数量需要用K相减以排除干扰
    • 比如2 4 6 8 9 end = 4 pivot = 3 K=4,得出的结果为2,说明包括枢轴,右边有两个值都大于第K大值所以需要让K减去该值

代码

import java.util.*;

public class Solution {
    /**
     * 寻找第K大
     *
     * @param a 数组
     * @param n 数组长度
     * @param K 第K大
     * @return int
     * @apiNote
     * @since 2023/1/9 19:52
     */
    public int findKth(int[] a, int n, int K) {
        return QuickSort(a, 0, n - 1, K);
    }

    /**
     * 使用快速排序返回第K大的元素
     *
     * @param array 待排数组
     * @param start 排序上界
     * @param end   排序下界
     * @param K     第K大
     * @return int 第K大的元素
     * @apiNote
     * @since 2023/1/9 20:02
     */
    public int QuickSort(int[] array, int start, int end, int K) {
        // 划分
        int pivot = Partition(array, start, end);
        // 判断枢轴距离第K大的位置
        // 当前枢轴恰好为第K大
        if (end - pivot + 1 == K) {
            return array[pivot];
        }
        // 如果枢轴位于第K大的左边,向右快排
        else if (end - pivot + 1 > K) {
            return QuickSort(array, pivot + 1, end, K);
        }
        // 如果枢轴位于第K大右边,向左快排
        else {
            // 注意向左快排时式子end - pivot + 1的值为大于K的元素的数量
            // 比如2 4 6 8 9 end = 4 pivot = 3 K=4,得出的结果为2,说明包括枢轴,右边有两个值都大于第K大值所以需要让K减去该值
            return QuickSort(array, start, pivot - 1, K - (end - pivot + 1));
        }

    }

    /**
     * 划分方法
     *
     * @param array 待划分数组
     * @param start 划分上界
     * @param end   划分下界
     * @return int 划分之后枢轴所在的最终位置
     * @apiNote 返回划分之后的枢轴位置
     * @since 2023/1/9 20:04
     */
    private int Partition(int[] array, int start, int end) {
        // 以第一个元素作为枢轴
        int pivot = array[start];
        // 使用while循环找出枢轴的最终位置
        while (start < end) {

            while (start < end && array[end] >= pivot) {
                // 如果右边的值大于枢轴,则移动索引
                end--;
            }
            // 如果右边的值比枢轴小移动到左端
            array[start] = array[end];
            while ((start < end && array[start] <= pivot)) {
                // 如果左边的值小于枢轴则,移动索引
                start++;
            }
            // 如过左边的值比枢轴大移动到右端
            array[end] = array[start];
        }
        // 最后空出来的start的位置则是现在枢轴元素应该存在的位置,将该枢轴元素赋值给该位置
        array[start] = pivot;
        // 返回枢轴所在的位置,以便下一次划分
        return start;
    }
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务