利用快速排序解决区间第k大

leetcode 215. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

显然,可以冒泡排序一轮后选择倒数第k个元素,但时间复杂度为n2,如果要优化这个算法,我们应该使用快速排序.

关于快速排序的实现在这篇文章中已有说明:http://t.csdnimg.cn/qp6z7

我们知道,快排一轮后,基准元素就已经排好,位于排序的最终位置.数组中基准元素左边的元素都比它小,右边的元素都比他大。这样我们就有了解决这个问题的思路:

先用一轮快速排序确定基准元素的最终位置,如果发现基准元素是第k+1大,K+2大...那就说明第k大的元素比基准元素大,在基准元素右侧,则用递归的方式到右侧寻找;如果发现基准元素是第k-1大,k-2大....那就说明第k大的元素比基准元素小,在基准元素左侧,用递归的方式到左侧寻找;如果发现基准元素是第k大,则它就是所寻找的元素,直接返回。

代码如下:

public static int theKthNumber(int[] arr,int low,int high,int k){
    int index = low - 1;
    int pivot = arr[high];
    for (int i = low; i < high; i++){
        if (arr[i] < pivot){
            index++;
            int temp = arr[i];
            arr[i] = arr[index];
            arr[index] = temp;
        }
    }
    //low到index都比基准值arr[high]小,index+1是arr[high]的最终位置
    index++;
    arr[high] = arr[index];
    arr[index] = pivot;
    //如果排好序的基准元素是第k大(最终位置是arr.length-k),返回该元素;否则递归
    if (index == arr.length - k){
        return arr[index];
    }else if (index < arr.length - k){
        return theKthNumber(arr,index+1,high,k); //如果是第k+1,k+2...大,就到右边找
    }else {
        return theKthNumber(arr,low,index-1,k);  //如果是第k-1,k-2...大,就到左边找
    }
}

上述代码完全能跑通过,但到leetcode上面一跑起来,却超时了......这是为何?因为代码没有对极端情况进行处理。快速排序在最坏的情况下会有n2的复杂度,十分麻烦,如果给你的是这种测试样例的话,就会超时。处理办法是在for循环前对基准元素做一个处理,不直接选arr[high]做基准元素,而是随机选取一个元素与arr[high]交换位置后,再选取arr[high]作为基准元素。

这样就可以通过leetcode的测试了。

这题除了快速排序的方式外,还可以用堆结构做,下次再谈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值