1. 程式人生 > 實用技巧 >陣列中的第K個最大元素

陣列中的第K個最大元素

陣列中的第K個最大元素

在未排序的陣列中找到第k個最大的元素。請注意,你需要找的是陣列排序後的第k個最大的元素,而不是第k個不同的元素。

示例

輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5
輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4

題解

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var findKthLargest = function(arr, k) {
    var adjustHeap = function(arr, i, n) {
        for(let k=2*i+1; k<n; k=2*k+1){
            let parent = arr[i];
            if(k+1 < n && arr[k] < arr[k+1]) ++k;
            if(parent < arr[k]){
                [arr[i], arr[k]] = [arr[k], arr[i]];
                i = k;
            }else{
                break;
            }
        }
    }
    var n = arr.length;
    for(let i = Math.floor(n/2-1); i>=0; --i) adjustHeap(arr, i, n);
    var target = 0;
    for(let i=n-1; i>=n-k; --i){
        target = arr[0];
        if(i-1>=n-k){
            [arr[0], arr[i]] = [arr[i], arr[0]];
            adjustHeap(arr, 0, i);
        }
    }
    return target;
};

思路

採用大頂堆的資料結構解決問題,大頂堆要求根節點的關鍵字既大於或等於左子樹的關鍵字值,又大於或等於右子樹的關鍵字值並且為完全二叉樹,首先定義adjustHeap函式左調整堆使用,首先以i作為雙親元素的下標,以k作為左孩子的下標,當右孩子存在時判斷右孩子是否大於左孩子,大於左孩子則將k作為右孩子的指向下標,然後判斷雙親值與k指向的孩子的節點值的大小,如果孩子值大於雙親值則交換,並且以k作為雙親節點沿著路徑繼續向下調整,否則就結束本次迴圈,然後定義n作為陣列長度,之後將堆中每個作為雙親節點的子樹進行調整,使整個樹符合大頂堆的特徵,之後進行k次迴圈,由於是大頂堆且已調整完成將頂堆的頂值也就是最大值取出賦值給target

,之後判斷是否需要進一步調整,如果需要則交換頂端值與最後一個值,然後調整頂堆符合大頂堆的條件,同樣取出頂堆最大值,取出k次即可完成。

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://leetcode-cn.com/problems/kth-largest-element-in-an-array/