BM47-寻找第K大

题目

有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。

给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。

要求:时间复杂度 O(nlogn),空间复杂度 O(1)。

数据范围:0≤n≤1000, 1≤K≤n,数组中每个元素满足 0≤val≤10000000。

示例1

输入:[1,3,5,2,2],5,3

返回值:2

示例2

输入:[10,10,9,9,8,7,5,6,4,3,4,2],12,3

返回值:9

说明:去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9。


思路

快排分区partition思想,当分区函数返回的索引值 = n - k,该分区元素就是要找的元素。时间复杂度O(n)。


代码

import java.util.*;

public class Solution {
    public int findKth(int[] a, int n, int K) {
        //第k大元素的索引为n - k
        //[1,2,3,4,5]第2大元素4对应的索引为5 - 2 = 3
        return findKthLargestInternal(a, 0, a.length - 1, a.length - K);
    }

    /**
     * 在nums[l...r]找到索引为k元素
     * @param nums
     * @param l
     * @param r
     * @param k
     * @return
     */
    private int findKthLargestInternal(int[] nums, int l, int r, int k) {
        if (l > r) {
            //空区间
            return -1;
        }
        int p = partition(nums, l, r);
        if (p == k) {
            //此时索引p对应的元素恰好就是要查找的元素
            return nums[p];
        } else if (k > p) {
            //在右半区间接着找
            return findKthLargestInternal(nums, p + 1, r, k);
        }
        //此时k < p,在左半区间找
        return findKthLargestInternal(nums, l, p - 1, k);
    }

    /**
     * 分区函数
     * @param nums
     * @param l
     * @param r
     * @return
     */
    private int partition(int[] nums, int l, int r) {
        //默认选择第一个元素作为分区点
        int v = nums[l];
        //i是当前处理的元素
        //arr[l + 1...j] < v
        //最开始没有元素 < v
        int j = l;
        //arr[j + 1...i) >= v也是空区间
        for (int i = l + 1; i <= r; i++) {
            if (nums[i] < v) {
                swap(nums, j + 1, i);
                j++;
            }
        }
        //j对应 <v 的最后一个元素
        swap(nums, l, j);
        return j;
    }

    /**
     * 交换三连操作
     * @param nums
     * @param i
     * @param j
     */
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值