K-th smallest/largest element in unsorted array

LeetCode problem 215. Kth Largest Element in an Array.

## Problem description

Find the **k**th largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1
* **Input:** `[3,2,1,5,6,4]` and k = 2
* **Output:** 5

Example 2
* **Input:** `[3,2,3,1,2,4,5,5,6]` and k = 4
* **Output:** 4

Note
You may assume k is always valid, 1 ≤ k ≤ array's length.
## Analysis

For finding the k-th largest element, we can use a **min-heap** with size *k* to process all the elements in the array.

Why use a **min-heap**?
* If we have processed less than *k* elements in the array, we can just add to the heap.
* But if we already have *k* elements in the heap, for each element hereafter, the following steps must be done:
	1. Check if the current element is smaller than any elements we have processed so far.
	2. If the current element is smaller than the minimum element in the heap, we do not need to do nothing. However, if the current element is greater than the minimum element in the heap, then we need to **pop the original smallest element in the heap**, and then insert the current element.
* Also, after processing, the min-heap's minimum element is the result we want.

Similarly, if we want to find the *k*-th smallest index, we use a *max-heap* instead.

### Complexity analysis

#### Time complexity

Let there be a total of *n* nodes, so we have *n* iterations in total.

Each time we update the min-heap, the time complexity is:

1. Pop minimum from heap, if the current element to process is greater than minimum. — O(log *k*)
2. Insert the current element to the heap. — O(log *k*)

So total time complexity is **O(n log *k*)**.

#### Space complexity

Stack
The space complexity on stack is O(1), since we have just used a fixed set of variables and no recursion.
Heap
The space complexity on heap is O(*k*), which involves the min-heap.
So the total space complexity is **O(*k*)**.

## Solution

### C++

```
class Solution {
private:
 static bool minHeapComparator(const int& a, const int& b) {
 return a >= b;
 }

 typedef std::priority\_queue<int, std::vector<int>,
 decltype(&minHeapComparator)> MinHeap;

 static MinHeap& checkPush(MinHeap& minHeap, const int& k, const int& val) {
 if (minHeap.size() >= k) {
 // pop and push if min heap is full, and current value > current min
 if (minHeap.top() < val) {
 minHeap.pop();
 minHeap.push(val);
 }
 }
 else {
 minHeap.push(val);
 }
 return minHeap;
 }

public:
 int findKthLargest(vector<int>& nums, const int& k) {
 // create min-heap
 MinHeap minHeap(minHeapComparator);

 // process all elements
 for (int i = 0; i < nums.size(); ++i) {
 minHeap = checkPush(minHeap, k, nums[i]);
 }
 return minHeap.top();
 }
};

```

Here is the version using a `MinHeapComparator` class:

```
class Solution {
private:
 class MinHeapComparator {
 public:
 constexpr bool operator()(const int& a, const int& b) const {
 return a >= b;
 }
 };

 typedef std::priority\_queue<int, std::vector<int>, MinHeapComparator> MinHeap;

 static MinHeap& checkPush(MinHeap& minHeap, const int& k, const int& val) {
 if (minHeap.size() >= k) {
 // pop and push if min heap is full, and current value > current min
 if (minHeap.top() < val) {
 minHeap.pop();
 minHeap.push(val);
 }
 }
 else {
 minHeap.push(val);
 }
 return minHeap;
 }

public:
 int findKthLargest(vector<int>& nums, const int& k) {
 // create min-heap
 MinHeap minHeap;

 // process all elements
 for (int i = 0; i < nums.size(); ++i) {
 minHeap = checkPush(minHeap, k, nums[i]);
 }
 return minHeap.top();
 }
};

```

Here is a revised version using `std::greater_equal` as comparator:

```
class Solution {
private:

 typedef std::priority\_queue<int, std::vector<int>,
 std::greater\_equal<int>> MinHeap;

 static MinHeap& checkPush(MinHeap& minHeap, const int& k, const int& val) {
 if (minHeap.size() >= k) {
 // pop and push if min heap is full, and current value > current min
 if (minHeap.top() < val) {
 minHeap.pop();
 minHeap.push(val);
 }
 }
 else {
 minHeap.push(val);
 }
 return minHeap;
 }

public:
 int findKthLargest(vector<int>& nums, const int& k) {
 // create min-heap
 MinHeap minHeap;

 // process all elements
 for (int i = 0; i < nums.size(); ++i) {
 minHeap = checkPush(minHeap, k, nums[i]);
 }
 return minHeap.top();
 }
};

```

### Java

```
class Solution {
 private static class MinHeapComparator implements Comparator<Integer> {
 @Override
 public int compare(Integer o1, Integer o2) {
 if (o1 < o2) {
 return -1;
 }
 else if (o1 == o2) {
 return 0;
 }
 else {
 return 1;
 }
 }
 }

 private static PriorityQueue<Integer> checkPush(PriorityQueue<Integer> minHeap,
 int k, int val) {
 if (minHeap.size() >= k) {
 // pop and push if min heap is full, and current value > current min
 if (minHeap.peek() < val) {
 minHeap.poll();
 minHeap.offer(val);
 }
 }
 else {
 minHeap.offer(val);
 }
 return minHeap;
 }

 public int findKthLargest(int[] nums, int k) {
 // create a min-heap
 PriorityQueue<Integer> minHeap = new PriorityQueue<>(k, new MinHeapComparator());

 // process all elements
 for (int i = 0; i < nums.length; ++i) {
 checkPush(minHeap, k, nums[i]);
 }

 return minHeap.peek();
 }
}

```

Or, for a *min-heap*, we can omit the comparator:

```
class Solution {
 private static PriorityQueue<Integer> checkPush(PriorityQueue<Integer> minHeap,
 int k, int val) {
 if (minHeap.size() >= k) {
 // pop and push if min heap is full, and current value > current min
 if (minHeap.peek() < val) {
 minHeap.poll();
 minHeap.offer(val);
 }
 }
 else {
 minHeap.offer(val);
 }
 return minHeap;
 }

 public int findKthLargest(int[] nums, int k) {
 // create a min-heap
 PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);

 // process all elements
 for (int i = 0; i < nums.length; ++i) {
 checkPush(minHeap, k, nums[i]);
 }

 return minHeap.peek();
 }
}

```

## Notes

### C++

* `std::priority_queue`
	+ A `std::priority_queue` class takes three type arguments:
		1. `T` — the type of elements in the priority queue.
		2. `Container` — the container of the elements. Default is `std::vector`.
		3. `Compare` — a function that compares two arguments of the element type in the `std::priority_queue` instance, and returns a `bool` value specifying whether the first element goes before the second element. Default is `std::less`.
	+ If element `a` goes *before* element `b`, by the definition of the comparison function, then during the repeated pop process, element `a` is popped *after* element `b`.
		- In a *min-heap*, larger elements *go before* small elements; when popping repeatedly, smaller elements are popped *earlier than* larger elements.
		This is the comparison function for a min-heap:
		```
		bool minHeapComparator(const int& a, const int& b) {
		 return a >= b;
		}

		```
		- In a *max-heap*, the popping order is the opposite of the popping order of a min-heap.
		This is the comparison function for a max-heap:
		```
		bool maxHeapComparator(const int& a, const int& b) {
		 return a <= b;
		}

		```
	+ Use `decltype` to get the type of the comparison function.
	+ Use `typedef` to provide an alias of the priority queue type parameters, to make the code simpler, cleaner, and more readable.
		- Example:
		```
		typedef std::priority\_queue<int, std::vector<int>,
		 decltype(&minHeapComparator)> MinHeap;

		```
		- In this case the min-heap initialization will be as follows:
		```
		MinHeap minHeap(minHeapComparator);

		```
	+ If we use a `MinHeapComparator` class, the code would be as follows:
	```
	class MinHeapComparator {
	public:
	 constexpr bool operator()(const int& a, const int& b) const {
	 return a >= b;
	 }
	};

	typedef std::priority\_queue<int, std::vector<int>,
	 MinHeapComparator> MinHeap;

	```
* Comparison utilities
	+ `std::less`
	+ `std::less_equal`
	+ `std::greater`
	+ `std::greater_equal`

### Java

* `PriorityQueue`
* `Comparator`
	+ To compare these two objects we need to implement this method: `int compare(T o1, T o2)`
* `Comparable`
	+ To compare one object of a class that implements `Comparable` with another object of the same class, we need to implement this method: `int compareTo(T o)`.
	+ To allow the `PriorityQueue` to determine if one object exists in the queue using `public boolean contains(Object o)`, we need to override the `public boolean equals(Object obj)` method. Note that the `equals` method passes in an argument of type `Object`, so that type-casting from `Object` to the actual class is necessary to compare the members of the other object.

## External links

* K largest (or smallest) elements in an array | added Min Heap method (Archive)