利用类快速排序求数组中第k大的值

如果要求出一个数组中第k大的值可以采用以下策略:

  • 排序法:利用各种排序算法对数组排序后,再找到第k大的数。利用计数排序可以将时间复杂度压缩到O(N)
  • 部分排序法,利用冒泡、选择排序,或者堆排序,依次找第1大、第2大、…第k大的值
  • 类快速排序方法

我们以一个例子来理解类快排的方式:
比如找输入数组arr [4, 5, 7, 6, 3, 1, 2, 10, 9],K 为 4,即找数组中第4大的数

我们先以数组arr[0],也就是4为基准,利用快排的原理,将比4小的放左边,比4大的放右边。第1步
因为右边有5个数字比4大,此时4肯定是第6大的数字。并且可以知道第4大的数字肯定在右边。

接着对右边进行相同的操作,右边第一个元素6作为基准值,小的放左边,大的放右边。
第2步
此时6的右边有3个数比6大,就说嘛6就是第4大的元素。找到了第4大的元素,结束程序。

代码实现

function findKthOfN (arr, k) {
  function findKthOfNByQuickSort (arr, low, high, k) {
    var baseIndex = low, leftIndex = low, rightIndex = high, splitIndex
    while (1) {
      while (arr[leftIndex] <= arr[baseIndex]) {
        leftIndex ++
      }
      while (arr[rightIndex] >= arr[baseIndex]) {
        rightIndex --
      }
      
      if (leftIndex >= rightIndex) {
        leftIndex = leftIndex > high ? high : leftIndex
        rightIndex = rightIndex < low ? low : rightIndex
        splitIndex = arr[leftIndex] < arr[rightIndex] ? leftIndex : rightIndex
        break
      }
      
      
      var tmp = arr[leftIndex]
      arr[leftIndex] = arr[rightIndex]
      arr[rightIndex] = tmp

    }
    tmp = arr[splitIndex]
    arr[splitIndex] = arr[baseIndex]
    arr[baseIndex] = tmp
    // 完成快排的分大小值
    if (arr.length - splitIndex === k) return arr[splitIndex]
    if (arr.length - splitIndex > k) return findKthOfNByQuickSort(arr, splitIndex+1, high, k)
    if (arr.length - splitIndex < k) return findKthOfNByQuickSort(arr, low, splitIndex-1, k)
  }
  return findKthOfNByQuickSort(arr, 0, arr.length-1, k)
}

将上诉代码改一个地方就变成了,求某个数组最大的K个元素,但是求得的最大K个元素是无序的。

function findTopK (arr, k) {
// ...
if (arr.length - splitIndex === k) return arr.slice(splitIndex)
// ...
}

运行结果如下:

var arr = [4, 5, 7, 6, 3, 1, 2, 10, 9]
console.log(findKthOfN(arr, 4)) // 6
console.log(findTopK(arr, 4)) // [ 6, 7, 10, 9 ]

扩展

在不排序的情况下求数组的中位数。
相当于K = 2/N,也属于求数组中第K大的数。

function getMid (arr) {
  var mid, len = arr.length
  if (len % 2 === 0) {
    mid = findKthOfN (arr, len/2)
    mid += findKthOfN (arr, len/2 + 1)
    mid /= 2
  } else {
    mid = findKthOfN (arr, Math.ceil(len/2))
  }
  return mid
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值