力扣-215. 陣列中的第K個最大元素

DawnTraveler發表於2024-06-20

1.題目

題目地址(215. 陣列中的第K個最大元素 - 力扣(LeetCode))

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

題目描述

給定整數陣列 nums 和整數 k,請返回陣列中第 k 個最大的元素。

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

你必須設計並實現時間複雜度為 O(n) 的演算法解決此問題。

示例 1:

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

示例 2:

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

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

2.題解

可以參考P1923 【深基9.例4】求第 k 小的數

2.1 nth_element的使用

思路

在強大的STL庫中存在一個神奇的函式,那就是nth_element,這個函式主要用來將陣列元素中第k小的整數排出來並在陣列中就位,隨時呼叫,可謂十分實用。
他的時間複雜的為O(n), 原因是他不要像排序那樣確定每個元素都在自己應該在的位置上,它只要保證指定的k位置左邊元素均小於它,右邊元素均大於它即可。
故實際實現使用分治演算法思想,只需要首尾指標對於陣列進行一次遞推遍歷即可,這裡先講nth_element函式的使用方法,在2.2中詳細介紹實現。
函式語句:nth_element(陣列名,陣列名+第k小元素,陣列名+元素個數)

程式碼

  • 語言支援:C++

C++ Code:


class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int n = nums.size();
        nth_element(nums.begin(), nums.begin() + n - k, nums.end());
        return nums[n - k];
    }
};

2.2 分治演算法

思路

我們使用分治思想,每次將整個區間分為左右兩個區域,選取一個基準點後,透過首尾指標不斷逼近,中間透過交換保證r左側的區間全部小於等於currNum, l右側的區間全部大於等於currNim
直到最後l > r結束迴圈,此時已經可以保證[begin, r] 和 [l, end]兩個區域都是"有序的",也就是左邊均小於等於currNum,右邊均大於等於currNum
我們再來判斷目標位置k所處的位置,分三種情況,每次都可以二分縮小一半查詢範圍:
1.k <= r, 去左半區間[begin, r]繼續尋找
2.k >= l, 去右半區間[l, end]繼續尋找
3.r < k < l. 這種情況比較特殊,具體可以見情況二圖片,必然是 l - r = 2, k = r + 1 = l - 1的情況,
否則如果像情況一,l - r = 1, 那麼必然有 k <= r 或者 k >= l, 而不可能存在r < k < l

大致的情況有以下兩種:
情況一:

情況二:

程式碼

class Solution {
public:
    int ans = 0;
    void sortNum(vector<int>& nums, int begin, int end, int k){
        if(begin == end){
            ans = nums[begin];
            return;
        }
        int currNum = nums[begin + (end - begin) / 2];
        int l = begin, r = end;
        while(l <= r){
            while(nums[l] < currNum) l++;
            while(nums[r] > currNum) r--;
            if(l <= r) swap(nums[l++], nums[r--]);
        } 
        if(k <= r) sortNum(nums, begin, r, k);
        else if(k >= l) sortNum(nums, l, end, k);
        else sortNum(nums, r + 1, l - 1, k);
    }
    int findKthLargest(vector<int>& nums, int k) {
        int n = nums.size();
        sortNum(nums, 0, n - 1, n - k);
        return nums[n - k];
    }
};

相關文章