20200629
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度
先排序(倒序)后直接取值
实现 sort 排序功能,循环原数组把元素逐个放到排序数组中:
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function (nums, k) {
// nums.sort((a, b) => b - a).slice(0, k)
// return nums[k - 1]
let sortArr = []
for (let i = 0; i < nums.length; i++) {
if (sortArr.length === 0) {
sortArr[0] = nums[i]
} else if (sortArr[sortArr.length - 1] >= nums[i]) {
sortArr[sortArr.length] = nums[i]
} else if (sortArr[0] <= nums[i]) {
sortArr.unshift(nums[i])
} else {
let len = sortArr.length
for (let j = 0; j < len; j++) {
if (sortArr[j] <= nums[i]) {
sortArr.splice(j, 0, nums[i])
break
}
}
}
}
return sortArr[k - 1]
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function (nums, k) {
// 替换指定位置两个数
function swap(a, i, j) {
var tmp = a[i]
a[i] = a[j]
a[j] = tmp
}
function quickSelect(a, left, right, index) {
let q = randomPartition(a, left, right)
// 如果index即假设第k大位置数的索引
// 大于基准数的索引,则缩小范围到:q+1 到 right
// 小于基准数的索引,则缩小范围到:left 到 q - 1
// 等于基准数的索引,则当前位置就第k大的值,返回
if (q == index) {
return a[q]
} else {
return q < index
? quickSelect(a, q + 1, right, index)
: quickSelect(a, left, q - 1, index)
}
}
// 任意取left到right中间一个数放到right位置做基准数据
// 此部分逻辑可不用,直接去left或者right上的值做基准(默认用right做基准)
function randomPartition(a, left, right) {
let i = Math.floor(Math.random() * (right - left + 1)) + left
swap(a, i, right)
return partition(a, left, right)
}
// 循环left到right中数据是right的左侧都小于等于它,并返回并返回基准数在数组有多少数小于它(即第几大)
function partition(a, left, right) {
let x = a[right],
i = left - 1
// 如果指针上在left位置上,数据小于right上的数据:swap(a, left, j)
// 如果指针上在j位置上,数据小于right上的数据:swap(a, left++, j)
for (let j = left; j < right; ++j) {
if (a[j] <= x) {
swap(a, ++i, j)
}
}
// 上面的循环如果i等于j其j等于right时,递归时则无法终止
// 则单独替换第i+1上和right上的数
swap(a, i + 1, right)
return i + 1
}
return quickSelect(nums, 0, nums.length - 1, nums.length - k)
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function (nums, k) {
// 替换指定位置两个数
function swap(a, i, j) {
let tmp = a[i]
a[i] = a[j]
a[j] = tmp
}
// 遍历数组分别对每个元素判断其是否大于左右的值
// 因为比较范围为 x-1到x+1则循环一半就可以遍历数组
function buildMaxHeap(a, len) {
for (let i = parseInt(len / 2, 10); i >= 0; --i) {
maxHeapify(a, i, len)
}
}
// 指针指向i
// 如果两边的数字大于它则用较大的数字替换它
// 递归比较知道查到最大值结束
function maxHeapify(a, i, len) {
let left = i * 2 + 1,
right = i * 2 + 2,
largest = i
if (left < len && a[left] > a[largest]) {
largest = left
}
if (right < len && a[right] > a[largest]) {
largest = right
}
if (largest != i) {
swap(a, i, largest)
maxHeapify(a, largest, len)
}
}
let len = nums.length
buildMaxHeap(nums, len)
for (let i = nums.length - 1; i >= nums.length - k + 1; --i) {
swap(nums, 0, i)
--len
maxHeapify(nums, 0, len)
}
return nums[0]
}
博客: 小书童博客(http://gaowenju.com)
公号: 坑人的小书童