【LeetCode-數組】數組中的第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

說明:

  • 你可以假設 k 總是有效的,且 1 ≤ k ≤ 數組的長度。

題目鏈接: https://leetcode-cn.com/problems/kth-largest-element-in-an-array/

思路1

升序排序,然后輸出第 n-k 個元素(第 k 大)。代碼如下:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end());
        return nums[nums.size()-k];
    }
};
  • 時間復雜度:O(nlogn)
    快速排序的時間復雜度。
  • 空間復雜度:O(1)

思路2

使用小根堆,小根堆的堆頂元素是堆中最小的元素。所以,我們遍歷數組,將數組中的元素加入堆中,然后保持堆的大小為 k,這樣數組遍歷結束后的堆中的元素就是數組中前 k 大的元素,堆頂元素是堆中最小元素,也就是第 k 大的元素。代碼如下:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int, vector<int>, greater<int>> q;
        for(int i=0; i<nums.size(); i++){
            q.push(nums[i]);
            if(q.size()>k) q.pop();
        }
        return q.top();
    }
};
  • 時間復雜度:O(nlogk)
    向堆中添加一個元素的時間復雜度為 logk,添加 n 次,所以為 nlogk。
  • 空間復雜度:O(k)

思路3

使用快速排序中的 partition 過程來做。partition 過程如下:

  • 找一個比較的基准,例如選取數組的第一個元素;
  • 設置兩個指針 i=0,j=nums.size()-1;
  • 如果 i<j,循環:
    • 從數組尾從后向前遍歷,找到第一個小於基准的元素 nums[i];
    • 從數組頭從前向后遍歷,找到第一個大於基准的元素 nums[j];
    • 交換 nums[i] 和 nums[j];
  • 交換 nums[i] 和 nums[left]。

一次 partition 之后,nums[i] 之前的數字都小於等於 nums[i],nums[i] 之后的數字都大於等於 nums[i],nums[i] 的位置已經確定,也就是 nums[i] 是數組 nums 中第 i 小的元素,如果 i==nums.size()-k(第 k 大元素),則返回 nums[i],否則根據 i 和 nums.size()-k 的大小關系,使用類似於二分查找的方法縮小 partition 的范圍。具體代碼如下:

class Solution {
public:
    int ans = -1;
    int findKthLargest(vector<int>& nums, int k) {
        int left = 0;
        int right = nums.size()-1;
        int target = nums.size()-k;
        while(true){    // while(left<=right) 也行
            int idx = partition(nums, left, right);
            if(idx==target) return nums[idx];
            else if(idx<target){
                left = idx+1;
            }else if(idx>target){
                right = idx-1;
            }
        }
        return -1;
    }

    int partition(vector<int>& nums, int left, int right){
        int base = nums[left];
        int i = left;
        int j = right;
        while(i<j){
            while(nums[j]>=base && i<j) j--;
            while(nums[i]<=base && i<j) i++;
            swap(nums[i], nums[j]);
        }
        swap(nums[i], nums[left]);
        return i;
    }
};

這種寫法參考了這篇題解

  • 時間復雜度:O(n)
  • 空間復雜度:O(1)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM