成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊TopK 算法的多種實(shí)現(xiàn)

開發(fā) 前端
TopK,即求數(shù)組的最小(或最大)的 k 個數(shù),且不要求這些數(shù)要排序返回。

我是前端西瓜哥,今天來整下 TopK 算法。

TopK,即求數(shù)組的最小(或最大)的 k 個數(shù),且不要求這些數(shù)要排序返回。

這是一個非常經(jīng)典的面試題。解法也是相當(dāng)?shù)亩啵茌^好考察面試者的數(shù)據(jù)結(jié)構(gòu)與算法基礎(chǔ)。

求最小和最大的思路是一樣的,我們假設(shè)要求的是最小的 k 個數(shù)。

對應(yīng)的 LeetCode 題目地址有兩個:

  • 《劍指 Offer(第 2 版)》第 40 題:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
  • 《程序員面試經(jīng)典(第 6 版)》17.14 題:https://leetcode-cn.com/problems/smallest-k-lcci/

排序

最簡單的方式是全排序,即對數(shù)組的所有元素都進(jìn)行升序排序,然后取前面的 k 個數(shù)。通常都會用編程語言自帶的排序 API,正確性有所保證。

function getLeastNumbers(arr: number[], k: number): number[] {
return arr.sort((a, b) => a - b).slice(0, k);
};

實(shí)際開發(fā)中如果有這個需求,且數(shù)據(jù)量不大,用自帶的排序方法是最穩(wěn)妥的。

因?yàn)榕判蚍椒ǖ讓油ǔJ强炫胚@些時(shí)間復(fù)雜度優(yōu)秀的排序算法,所以全排序的時(shí)間復(fù)雜度是 O(n*log(n)。

在全排序的基礎(chǔ)上,其實(shí)可以做個優(yōu)化,做 局部排序。有些算法(冒泡和選擇排序)的排序過程中,第 i 次迭代,都會使得第 i 個元素置于最終排好序后所在的位置。

這里我們看看魔改選擇排序的實(shí)現(xiàn):

function getLeastNumbers(arr: number[], k: number): number[] {
let min: number;
let minIdx: number;
for (let i = 0; i < k; i++) { // 這里迭代了 k
min = arr[i];
minIdx = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < min) {
min = arr[j];
minIdx = j;
}
}
[arr[i], arr[minIdx]] = [arr[minIdx], arr[i]]; // 交換
}
return arr.slice(0, k);
};

只要我們將原來的 n 次迭代改為 k 次迭代,就能獲得一個只是前 k 個數(shù)組元素做了排序的數(shù)組。

局部排序在原來時(shí)間復(fù)雜度為 O(n^2) 的排序算法的基礎(chǔ)上,優(yōu)化為了 O(k*n)。

當(dāng) k 很小時(shí),局部排序的效率要比全排序的高。

快排思想

快速排序的核心是 分治 和 分區(qū)。

限于篇幅,具體的快排原理和實(shí)現(xiàn)可以看我的這篇文章:經(jīng)典快速排序?qū)崿F(xiàn)

簡單來說,快排的實(shí)現(xiàn)是,每次取一個基準(zhǔn)值 pivot,將小于等于 pivot 的放到左區(qū)間,大于的放到右區(qū)間。然后針對這兩個區(qū)間繼續(xù)同樣操作,直到區(qū)間大小小于等于 1 為止,是自上而下的遞歸。

原來快排對兩個區(qū)間都要進(jìn)行遞歸,現(xiàn)在改造為選擇性地遞歸。

每一次分區(qū)(partition)后:

  • 如果 pivot 所在的位置小于 k,遞歸就可以結(jié)束了,此時(shí)數(shù)組的前 k 個數(shù)組元素就是最小的 k 個元素;
  • 如果 pivot 所在的位置在 k 的左側(cè),說明 pivot 的左區(qū)間可以不用排序了,小于等于 pivot 的值都在左側(cè)。然后對右區(qū)間進(jìn)行遞歸;
  • 如果 pivot 所在的位置在 k 的右側(cè),則 pivot 的右區(qū)間不用考慮了,需要對左區(qū)間遞歸。

這里有一個非常重要的點(diǎn):每次分區(qū)分后 pivot 所在索引的值就是整個數(shù)組排過序后應(yīng)該為的值。 這是我們可以不管其中一個區(qū)間的原因。

function getLeastNumbers(arr: number[], k: number): number[] {
partition(arr, 0, arr.length - 1, k);
return arr.slice(0, k);
};

function partition(arr: number[], lo: number, hi: number, k: number) {
if (lo >= hi) return;
const pivot = arr[hi]; // 這里可以改為隨機(jī)選擇 pivot
let i = lo;
for (let j = lo; j < hi; j++) {
if (arr[j] <= pivot) {
swap(arr, i, j);
i++;
}
}
swap(arr, i, hi);

// 原本的快排的 partition 的最后是這兩行,現(xiàn)在改為現(xiàn)在的下面這五行
// partition(arr, i + 1, hi, k);
// partition(arr, lo, i - 1, k);
if (i < k) {
partition(arr, i + 1, hi, k);
} else if (i > k) {
partition(arr, lo, i - 1, k);
}
}

function swap(arr: number[], i: number, j: number) {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}

平均時(shí)間復(fù)雜度是 O(n),最壞時(shí)間復(fù)雜度是 O(n^2)。不管怎樣總體上都比快排效率高,除非極端情況。

大頂堆

大頂堆是個完全二叉樹,特點(diǎn)是:任何一個節(jié)點(diǎn)的值都大于等于子樹任意一個節(jié)點(diǎn)的值。

我們創(chuàng)建一個大小為 k 的大頂堆。先放入 k 個元素。后面想放入新元素時(shí),先和堆頂元素(堆的最大值)對比。如果小于堆的最大元素,說明這個堆頂元素不合格,不可能為 TopK 的一員,將其出堆,然后讓新元素入堆;否則新元素不入堆。

一直這樣操作直到遍歷完整個數(shù)組。最后這個堆就是我們要的 TopK。

JavaScript 沒有內(nèi)置堆或優(yōu)先隊(duì)列這些數(shù)據(jù)結(jié)構(gòu),就暫且不實(shí)現(xiàn)了。

入堆的時(shí)間復(fù)雜度是 O(log k),要入堆 n 次,所以總的時(shí)間復(fù)雜度是 O(n*log k)。

如果你需要動態(tài)維護(hù) TopK,比如網(wǎng)站的每日排行榜,用大頂堆方案會更合適。

結(jié)尾

總的來說,快排思想的方案時(shí)間復(fù)雜度最低,大頂堆適合需要動態(tài)維護(hù) TopK 的情況,而全排序則適合寫業(yè)務(wù)代碼且數(shù)據(jù)量不大的時(shí)候。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2022-04-08 08:27:08

分布式鎖系統(tǒng)

2022-06-17 07:49:14

緩存LRU

2020-02-19 19:18:02

緩存查詢速度淘汰算法

2017-02-09 16:16:24

Java負(fù)載均衡算法

2019-12-11 10:50:06

JS圖片前端

2022-09-30 00:03:03

JS斷點(diǎn)線程

2022-10-08 00:07:00

JSV8調(diào)用棧

2024-12-23 15:05:29

2010-07-22 12:19:07

2023-05-30 07:58:01

谷歌搜索算法

2022-11-10 07:49:09

hash算法代碼

2022-06-28 15:13:12

Vuediff 算法

2023-11-28 09:19:12

2018-05-28 15:33:09

無監(jiān)督學(xué)習(xí)算法Python

2024-05-31 09:31:00

2021-07-14 14:05:24

Fragment項(xiàng)目結(jié)構(gòu)

2021-12-14 10:54:31

TopK面試排序法

2021-09-30 09:58:14

路徑總和二叉樹

2021-11-12 09:30:46

滑動窗口算法

2023-05-26 08:24:17

短信渠道模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 午夜精品久久久久久久久久久久 | 精品国产91 | 精品香蕉一区二区三区 | 成人在线一区二区三区 | 日本成人在线免费视频 | 精品欧美一区免费观看α√ | 91精品国产色综合久久不卡98 | 99九九视频 | 欧美精品一区二区在线观看 | 久久午夜视频 | 精品成人佐山爱一区二区 | 日韩精品一区二区三区在线播放 | 亚洲精品在线免费看 | 午夜爽爽男女免费观看hd | 蜜臀91视频 | 色婷婷亚洲一区二区三区 | 亚洲精品一区二区三区在线 | 精品亚洲一区二区三区 | 91精品国产91久久久久游泳池 | 国产精品国产自产拍高清 | 国产精品久久久久久婷婷天堂 | 男人天堂99 | 日韩国产一区 | 91成人在线视频 | 中文字幕精品视频 | 一级一片在线观看 | 久久久久国产精品午夜一区 | 日韩精品一区二区三区视频播放 | 国产男女猛烈无遮掩视频免费网站 | 日日操夜夜操天天操 | 欧美日韩综合一区 | 天天躁日日躁aaaa视频 | 在线观看精品视频网站 | 亚洲精品久久久久久久久久吃药 | 久久国产精品久久久久久 | av在线免费观看网址 | 一级黄色录像片子 | 日韩视频一区在线观看 | 免费看大片bbbb欧美 | 久久99精品国产99久久6男男 | 亚洲电影免费 |