[LeetCode] Kth Largest Element in an Array
Well, this problem has a naive solution, which is to sort the array in descending order and return the k-1
-th element. However, sorting algorithm gives O(nlogn)
complexity. Suppose n = 10000
and k = 2
, then we are doing a lot of unnecessary operations. In fact, this problem has at least two simple and faster solutions.
1 class Solution { 2 public: 3 int partition(vector<int>& nums, int left, int right) { 4 int pivot = nums[left]; 5 int l = left + 1, r = right; 6 while (l <= r) { 7 if (nums[l] < pivot && nums[r] > pivot) 8 swap(nums[l++], nums[r--]); 9 if (nums[l] >= pivot) l++; 10 if (nums[r] <= pivot) r--; 11 } 12 swap(nums[left], nums[r]); 13 return r; 14 } 15 int findKthLargest(vector<int>& nums, int k) { 16 int left = 0, right = nums.size() - 1; 17 while (true) { 18 int pos = partition(nums, left, right); 19 if (pos == k - 1) return nums[pos]; 20 if (pos > k - 1) right = pos - 1; 21 else left = pos + 1; 22 } 23 } 24 };
Heapsort
Well, this problem still has a tag "heap". If you are familiar with heapsort, you can solve this problem using the following idea:
- Build a max-heap for
nums
, setheap_size
to benums.size()
; - Swap
nums[0]
(after buding the max-heap, it will be the largest element) withnums[heap_size - 1]
(currently the last element). Then decreaseheap_size
by 1 and max-heapifynums
(recovering its max-heap property) at index0
; - Repeat 2 for
k
times and thek
-th largest element will be stored finally atnums[heap_size]
.
Now I paste my code below. If you find it tricky, I suggest you to read the Heapsort chapter of Introduction to Algorithms, which has a nice explanation of the algorithm. My code simply translates the pseudo code in that book :-)
1 class Solution { 2 public: 3 inline int parent(int idx) { 4 return (idx - 1) >> 1; 5 } 6 inline int left(int idx) { 7 return (idx << 1) + 1; 8 } 9 inline int right(int idx) { 10 return (idx << 1) + 2; 11 } 12 void max_heapify(vector<int>& nums, int idx) { 13 int largest = idx; 14 int l = left(idx), r = right(idx); 15 if (l < heap_size && nums[l] > nums[largest]) largest = l; 16 if (r < heap_size && nums[r] > nums[largest]) largest = r; 17 if (largest != idx) { 18 swap(nums[idx], nums[largest]); 19 max_heapify(nums, largest); 20 } 21 } 22 void build_max_heap(vector<int>& nums) { 23 heap_size = nums.size(); 24 for (int i = (heap_size >> 1) - 1; i >= 0; i--) 25 max_heapify(nums, i); 26 } 27 int findKthLargest(vector<int>& nums, int k) { 28 build_max_heap(nums); 29 for (int i = 0; i < k; i++) { 30 swap(nums[0], nums[heap_size - 1]); 31 heap_size--; 32 max_heapify(nums, 0); 33 } 34 return nums[heap_size]; 35 } 36 private: 37 int heap_size; 38 }
If we are allowed to use the built-in priority_queue
, the code will be much more shorter :-)
1 class Solution { 2 public: 3 int findKthLargest(vector<int>& nums, int k) { 4 priority_queue<int> pq(nums.begin(), nums.end()); 5 for (int i = 0; i < k - 1; i++) 6 pq.pop(); 7 return pq.top(); 8 } 9 };
Well, the priority_queue can also be replaced by multiset :-)
1 class Solution { 2 public: 3 int findKthLargest(vector<int>& nums, int k) { 4 multiset<int> mset; 5 int n = nums.size(); 6 for (int i = 0; i < n; i++) { 7 mset.insert(nums[i]); 8 if (mset.size() > k) 9 mset.erase(mset.begin()); 10 } 11 return *mset.begin(); 12 } 13 };