日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法:前K个最大的元素

發布時間:2023/12/6 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法:前K个最大的元素 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前幾天,阮一峰 和 winter 在前端九部組織了一個互面小組,目的是為了分享和解答面試遇到的面試題,感興趣的可以了解一下。

下面我就把我回答的一個問題整理出來分享給大家。

問題描述

題目是:算法,前 K 個最大的元素。

這個題目非常簡短,第一眼看上去可能不知道是什么意思。翻譯一下:

給定一個數字類型的數組和一個正整數 K,找出數組中前 K 個最大的元素。

這個題目網速也有很多的講解,我也是根據網上提供的一些思路來實現的,下面就是我根據其中三種方法的實現:

解答

解法一:

思路

最簡單的方法就是對數組進行排序,然后取前 K 位就可以了。

實現

/*** 查找前 K 個最大的元素* * @param {number[]} arr - 要查詢的數組* @param {number} k - 最大個數* * @return {number[]}*/ const findKMax = (arr, k) => {return arr.sort((a, b) => b - a).slice(0, k); } 復制代碼

解法二

思路

解法一用了 js 的 sort 來實現排序,但是復雜度比較高,數據量大的話會比較慢。仔細分析一下題目,找出前 K 個最大的元素,但并沒有要求對其排序,所以不用對所有的數都進行排序。分治法就會快很多:

假設有 n 個數存在數組 S 中,從數組 S 中隨機找一個元素 X,遍歷數組,比 X 大的放在 S1 中,比 X 小的放在 S2 中,那么會出現以下三種情況:

S1 的數字個數等于 K,結束查找,返回 S1; S1 的數字個數大于 K,繼續在 S1 中找取最大的K個數字; S1 的數字個數小于 K,繼續在 S2 中找取最大的 K-S1.length 個數字,拼接在 S1 后; 這樣遞歸下去,就可以找出答案來了。下面看具體的實現:

實現

/*** 分割數組* * @typedef {Object} Partition* @property {number[]} Partition.maxarr* @property {number[]} Partition.minarr* * @param {number[]} arr - 要分割的數組* * @returns {Partition} res - 返回結果*/ const partition = (arr) => {const length = arr.length; // 數組長度const mid = ~~(length / 2); // 取數組中間的位置,可隨機const middle = arr[mid]; // 數組中間的值const maxarr = []; // 比中間值大const minarr = []; // 比中間值小// 數組長度為 2 的要特殊處理if (length === 2) {maxarr.push(Math.max(arr[0], arr[1]));minarr.push(Math.min(arr[0], arr[1]));} else {arr.forEach((v, i) => {if (i !== mid) {if (v >= middle) {maxarr.push(v);} else {minarr.push(v);}}})// 將中間值放到 maxarr 的最后一位maxarr.push(middle);}return { maxarr, minarr } }/*** 查找前 K 個最大的元素* * @param {number[]} arr - 要查詢的數組* @param {number} k - 最大個數* * @return {number[]}*/ const findKMax = (arr, k) => {if (arr.length < k) {return arr;}// 分割數組const { maxarr, minarr } = partition(arr);if (maxarr.length === k) {return maxarr;}if (maxarr.length > k) {return findKMax(maxarr, k);}if (maxarr.length < k) {return maxarr.concat(findKMax(minarr, k - maxarr.length));} } 復制代碼

解法三

思路

可以取數組的前 K 位構建一個小頂堆(也叫最小堆),這么堆頂就是前 K 位最小的值,然后從 K+1 遍歷數組,如果小于堆頂,則將其交換,并重新構建堆,使堆頂最小,這么遍歷結束后,堆就是最大的 K 位,堆頂是前 K 位的最小值。

實現

/*** 小頂堆葉子節點排序* @param {number[]} arr - 堆* @param {number} i = 父節點* @param {length} i - 堆大小*/ const heapify = (arr, i, length) => {const left = 2 * i + 1; // 左孩子節點const right = 2 * i + 2; // 右孩子節點let minimum = i; // 假設最小的節點為父結點// 確定三個節點的最小節點if (left < length && arr[left] < arr[minimum]) {minimum = left;}if (right < length && arr[right] < arr[minimum]) {minimum = right;}// 如果父節點不是最小節點if (minimum !== i) {// 最小節點和父節點交換const tmp = arr[minimum];arr[minimum] = arr[i];arr[i] = tmp;// 對調整的結點做同樣的交換heapify(arr, minimum, length);}}/*** 構建小頂堆* 從 n/2 個節點開始,依次構建堆,直到第一個節點* * @param {number[]} arr */ const buildMinHeap = (arr) => {for (let i = Math.floor(arr.length / 2); i >= 0; i--) {heapify(arr, i, arr.length)}return arr; }/**·* 查找前 K 個最大的元素* * @param {number[]} arr - 要查詢的數組* @param {number} k - 最大個數* * @return {number[]}*/ const findKMax = (arr, k) => {// 取數組的前 K 位構建小頂堆const newArr = [...arr];const kMax = arr.slice(0, k)buildMinHeap(kMax);// 堆后面的進行遍歷,如果比堆頂大,則交換并重新構建堆for (let i = k; i < newArr.length; i++) {if (newArr[i] > kMax[0]) {const tmp = kMax[0];kMax[0] = newArr[i];newArr[i] = tmp;buildMinHeap(kMax);}}return kMax; } 復制代碼

總結

上面就是我對這個題目的三種解法,其實還有幾種解法,因為精力原因沒有探究,大家可以自己去網上了解一下。

上述解法如果有問題還請指正。

總結

以上是生活随笔為你收集整理的算法:前K个最大的元素的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。