1. 程式人生 > >LeetCode-215. 陣列中的第K個最大元素

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

題目

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

示例 1:

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

示例 2:

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

說明:

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

解題

  • 方法一 : 任意一種O(nlogn)演算法對陣列進行降序排序, 取下標為k - 1的陣列元素即可
  • 方法二 : 使用堆, 維護一個元素個數為k的最大堆, 將所有數字放入到最大堆中, 全部放完之後, 最大堆中最小的那個元素就是第k個最大的元素
  • 方法三 : 快速排序思想, 使用三路快排, 每次都將陣列分割成三部分, 每次只需要在其中一部分繼續尋找, 時間複雜度O(logn), 方法三程式碼如下:
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return partition(nums, 0, nums.length - 1, k);
    }
    
    // 在nums陣列[l...r]區間查詢第k個最大元素
    // 使用三路快排的partition操作, 設定標定點為v, 等於v的部分就是這部分元素在陣列中應該待的位置
// 判斷k是否在等於v的部分,如果在的話, 就直接返回nums[k]即可 // 如果k在小於v的部分, 就在小於v的部分繼,否則就在大於v的部分繼續尋找 private int partition(int[] nums, int l, int r, int k){ int mid = l + (r - l) / 2; swap(nums, l, mid); int v = nums[l]; int left = l - 1; // 設定nums[l...left]區間的元素都大於v int i = l;
// 設定nums[left+1...i)區間的元素都等於v, i表示當前要考察的元素 int right = r + 1; // 設定[right...r]區間的元素都小於v while(i < right){ if(nums[i] > v){ swap(nums, i, left + 1); left++; i++; } else if (nums[i] == v){ i++; } else { // nums[i] < v swap(nums, i, right - 1); right--; } } if(k -1 <= left){ return partition(nums, l, left, k); } else if (k - 1 >=right) { return partition(nums, right, r, k); } else { // left < k -1 < right , 表示第k個最大元素就在[left+1, right -1]這個區間中, 第k個最大元素已經處於它應該在的位置了,直接返回nums[k]即可 // 陣列下標從0開始, return nums[k - 1]; } } private void swap(int nums[], int i, int j){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }