如果要求出一个数组中第k大的值可以采用以下策略:
我们以一个例子来理解类快排的方式:
比如找输入数组arr [4, 5, 7, 6, 3, 1, 2, 10, 9]
,K 为 4,即找数组中第4大的数
我们先以数组arr[0],也就是4为基准,利用快排的原理,将比4小的放左边,比4大的放右边。
因为右边有5个数字比4大,此时4肯定是第6大的数字。并且可以知道第4大的数字肯定在右边。
接着对右边进行相同的操作,右边第一个元素6作为基准值,小的放左边,大的放右边。
此时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
}