You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@return {number[]}
*/
function swap(arr, i , j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 堆化
function heapify(arr, n, i){
// n 代表这颗树里面有n个节点。
// i 代表要对第i个节点做堆化操作
// 自上而下式堆化
if(i>=n){
return ;
}
let maxindex = i;
let c1 = 2i+1; //左子节点的值对应arr中的索引
let c2 = 2i+2; //右子节点的值对应arr中的索引
Activity
Malenconiaprincep commentedon Jun 3, 2020
plane-hjh commentedon Jun 3, 2020
简单粗暴
排序+
slice先把输入的
n个数排序,排序之后位于前面的k个数就是最小的k个数。但是这样的时间复杂度是
O(nlogn),并不是我们想要的快排
快排的 关键 在于先在数组中选择一个数字,接下来把数组中的数字分为两部分,比选择的数字小的数字移到数组的左边,比选择的数字大的数字移到数组的右边。这个函数可以这样实现
比第
k个数字小的所有数组都位于数组的左边,比第k个数字大的都位于右边时间复杂度为
O(n), 缺点是会修改到输入的数字备注:看了一早上这种方法的实现,脑子不够用了。附本人觉得的优秀答案解答
0undefined0 commentedon Jun 3, 2020
排序加获取
sisterAn commentedon Jun 3, 2020
这是一道典型的 Top k 问题
这种问题我们该怎么处理喃?
最简单的就是将数组进行排序(可以是最简单的快排),取前 K 个数就可以了,so easy
解答一:数组排序,取前 k 个数
代码实现:
复杂度分析:
注意:
在 V8 引擎 7.0 版本之前,数组长度小于10时,
Array.prototype.sort()使用的是插入排序,否则用快速排序。在 V8 引擎 7.0 版本之后就舍弃了快速排序,因为它不是稳定的排序算法,在最坏情况下,时间复杂度会降级到 O(n2)。
而是采用了一种混合排序的算法:TimSort 。
这种功能算法最初用于Python语言中,严格地说它不属于以上10种排序算法中的任何一种,属于一种混合排序算法:
在数据量小的子数组中使用插入排序,然后再使用归并排序将有序的子数组进行合并排序,时间复杂度为
O(nlogn)。解法二:构建大顶堆求 Top k问题
我们也可以通过构造一个大顶堆来解决,大顶堆上的任意节点值都必须大于等于其左右子节点值,即堆顶是最大值。
所以我们可以重数组中取出
k个元素构造一个大顶堆,然后将其余元素与大顶堆对比,如果小于堆顶则替换堆顶,然后堆化,所有元素遍历完成后,堆中的元素即为前k个最小值具体步骤如下:
k个数(0到k-1位),构造一个大顶堆k位开始遍历数组,每一个数据都和大顶堆的堆顶元素进行比较,如果大于堆顶元素,则不做任何处理,继续遍历下一元素;如果小于堆顶元素,则将这个元素替换掉堆顶元素,然后再堆化成一个大顶堆。代码实现:
复杂度分析:
利用堆求 Top k 问题的优势
这种求 Top k 问题是可以使用排序来处理,但当我们需要在一个动态数组中求 Top k 元素怎么办喃?
动态数组可能会插入或删除元素,难道我们每次求 Top k 问题的时候都需要对数组进行重新排序吗?那每次的时间复杂度都为 O(nlogn)
这里就可以使用堆,我们可以维护一个 K 大小的小顶堆,当有数据被添加到数组中时,就将它与堆顶元素比较,如果比堆顶元素大,则将这个元素替换掉堆顶元素,然后再堆化成一个小顶堆;如果比堆顶元素小,则不做处理。这样,每次求 Top k 问题的时间复杂度仅为 O(logk)
更多堆内容可查看 前端进阶算法9:看完这篇,再也不怕堆排序、Top K、中位数问题面试了
解法三:计数排序
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。它是一种典型的拿空间换时间的排序算法
代码实现:
复杂度分析:
同时V8也对数组提供了slow、fast存储,一定程度上提高了计数排序的性能,具体可查看 前端进阶算法2:从Chrome V8源码看JavaScript数组(附赠腾讯面试题)
leetcode
XW666 commentedon Apr 14, 2021
//使用冒泡排序
const countingSort = (arr, k) => {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
}
AAAngelina commentedon Apr 21, 2021
借鉴快排的思想
`var smallestK = function (arr, k) {
sort(arr, 0, arr.length - 1, k);
return arr.slice(0, k);
}
function sort(arr, l, r, k) {
if (l >= r) return;
let pos = quicksort(arr, l, r);
let n = pos - l + 1;
if (n === k) {
return;
} else if (n < k) {
sort(arr, pos + 1, r, k - n)
} else if (n > k) {
sort(arr, l, pos - 1, k)
}
}
function quicksort(arr, l, r) {
let baseval = arr[l], index = l;
while (l < r) {
while (l < r && arr[l] <= baseval) l++;
while (l < r && arr[r] > baseval) r--;
if (l < r) {
[arr[l], arr[r]] = [arr[r], arr[l]];
l++;
r--;
}
}
[arr[index], arr[l]] = [arr[l], arr[index]];
return l;
}`
Jet12138 commentedon Sep 8, 2022
/**
@PARAM {number[]} arr
@PARAM {number} k
@return {number[]}
*/
function swap(arr, i , j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 堆化
function heapify(arr, n, i){
// n 代表这颗树里面有n个节点。
// i 代表要对第i个节点做堆化操作
// 自上而下式堆化
if(i>=n){
return ;
}
let maxindex = i;
let c1 = 2i+1; //左子节点的值对应arr中的索引
let c2 = 2i+2; //右子节点的值对应arr中的索引
if(c1<n && arr[c1]>arr[i]){
maxindex = c1;
}
if(c2<n && arr[c2]>arr[maxindex]){
maxindex = c2;
}
if(maxindex !== i){
swap(arr, maxindex, i);
}
}
// 原地建堆,从后往前,自上而下式建大顶堆(顶元素是堆中最大的。)
function build_heap(arr, n){
let lastnode = n-1; // 堆数组的最后一个值的索引
let lastparent = Math.floor((lastnode-1)/2);
}
var getLeastNumbers = function(arr, k) {
let heap = [];
// 从 arr 中取出前 k 个数,构建一个大顶堆
for(let i=0; i<k; i++){
heap.push(arr[i]);
}
build_heap(heap, k);
for(let i= k; i<arr.length; i++){
if(arr[i]<heap[0]){
// 替换堆顶元素并堆化(自顶而下)
heap[0] = arr[i];
heapify(heap, k, 0);
}
}
return heap;
};