Heap Problems
Questions discussed
- Kth Largest Element in an Array (Medium)
- Find all K Largest Elements in the array
- Sort a K Sorted array
- Find K Closest Elements (Medium)
- Top K Frequent Elements (Medium)
- Top K Frequent Elements
- K Closest Points to Origin
Kth Largest Element in an Array (Medium)
Problem Statement
Given an integer array nums and an integer k, return the kth largest element in the array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
Examples
Constraints
- \(1 \leq\)
k
<=nums.size()
\(\leq\) \(10^4\) - \(- 10^4 \leq \text{nums[i]} \leq 10^4\)
Approach
- There are several approaches, in which 2 are the most efficient:
- use a
k
size min heap and put values into the heap until sequence runs out. - use the
buildHeap()
approach to build the given sequence into a heap, then remove top k times.
- use a
- The first approach takes \(O(N)\) time and no extra memory.
- The second approach takes \(O(N \log K)\) time and \(O(K)\) extra memory.
- If you are given a sequence with no ending (data stream) then the second one will be the better approach.
- Here in the solution we'll be using the second approach.
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> minHeap;
for (auto i:nums){
if (minHeap.size() != k){
// Until the min Heap is not of size `K` push elements
minHeap.push(i);
} else {
// Now the min Heap is of size K. Push one element [it may be the kth largest]
minHeap.push(i);
// If not the kth largest it'll be removed
// Otherwise the k-1th largest will be removed
minHeap.pop();
}
}
return minHeap.top();
}
};
Find all K Largest Elements in the array
Problem Statement
This problem is a bit different than the previous one. Here you have to return K largest elements from a given sequence. For example
flowchart LR
10-->12
12-->13
13-->167
167-->46
46-->2157
For the above sequence the \(K = 3\) largest elements should be the following:
flowchart LR
2157-->167-->46
Approach
- From the above code if we look closely enough, we find that after all the operations done the remaining elements in the
k
sized heap contains all the elements that are greater or equal to the \(K^{\text{th}}\) largest element in the given sequence. - So return all the elements from the heap.
C++ Code
std::vector<int> kLargestElements(std::vector<int> &vector, int k){
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
std::vector<int> out;
for (auto element:vector){
if (minHeap.size() != k){
minHeap.push(element);
} else {
minHeap.push(element);
minHeap.pop();
}
}
while (!minHeap.empty()){
out.push_back(minHeap.top());
minHeap.pop();
}
return out;
}
Sort a K Sorted array
Problem Statement
Each element in the array must be within the range k from it's desired position, Now sort the array as efficiently as possible.
Approach
- For each index, the corresponding sorted element is in the array is within
k
to the left andk
to the right of that index. - Now we make a min-heap of size k+1,
- Now we push first k+1 elements into the heap.
- Now for each index extract the min, then slide the window by 1 distance adding the \((k+1) + 1^{th}\) element to the heap and remove the min element from the min heap.
- In the next step do the same with \((k+1) + 2^{th}\) element, unitl this pointer reaches to the end.
- At the end extract the remaining min elements from the heap and add it to the out vector.
#include <iostream>
#include <queue>
#include <vector>
/*
🗿 Implementation for sorting a k sorted array using heap 🗿
🗿 Input is given a k sorted array [🗿 pass by address 🗿]
🗿 returns the sorted array.
*/
std::vector<int> kSortedArray(std::vector<int> &array, int k) {
int size = array.size();
int index = 0;
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
std::vector<int> out;
// initially push k element into the min heap
int nextuptoK = k + 1;
while (nextuptoK) {
minHeap.push(array[nextuptoK]);
nextuptoK--;
}
// Now move forward with the array and put one new element into the min heap and
// pop last element from the min heap [the minimum]. This popped element is the minimum element
// so put it into the out vector.
int window_last = k+2;
while (window_last != size) {
out.push_back(minHeap.top());
minHeap.pop();
minHeap.push(array[window_last]);
window_last++;
}
while(!minHeap.empty()) {
out.push_back(minHeap.top());
minHeap.pop();
}
return out;
}
Find K Closest Elements (Medium)
Problem Statement
Given a sorted integer array arr
, two integers k
and x
, return the k
closest integers to x
in the array. The result should also be sorted in ascending order.
An integer a is closer to x than an integer b if:
|a - x| < |b - x|
|a - x| == |b - x|
anda < b
Examples
Input: arr = [1,2,3,4,5], k = 4, x = 3
Output: [1,2,3,4]
Input: arr = [1,2,3,4,5], k = 4, x = -1
Output: [1,2,3,4]
Approach
- One approach could be that we subtract
x
from each element of the array and return whose difference with \(x\) is in \(\{0 \to k\}\) - Other approach would be to use a heap. Like the previous problem we pushed K
largest
orsmallest
elements into the array. Here what we'll do is- Make a minHeap,
Top K Frequent Elements (Medium)
Problem Statement
Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.
Examples
Constraints
1 <= nums.length <= 105
k
is in the range[1, the number of unique elements in the array]
.- It is guaranteed that the answer is unique.
Follow up: The algorithm's time complexity must be better than \(O(n \log n)\), where n is the array's size.
Approach
Code
Top K Frequent Elements
Find the problem on Leetcode \(\to\)
Problem Statement
Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order
Example
Input: nums = [1,12,2,34,124,124,12,31,23,123,12,312,3,123,123,123,12,31,23,123,123]
and k = 5
Output: [123,12,23,31,124]
Approach
- First we should make an unordered map to find the frequency of all the elements. We do not get that information by just looking at the elements of the array.
- After that once we have the frequency of all the elements, we'll push elements on to a min heap of size \(K\) based on the frequency of those elements.
- Making the size of the min heap limited to size \(K\) helps to keep track only the k most frequent elements, once we have a less frequent element, as it'll on the top of the min heap, we'll perform a heap pop.
Code
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
// first count all the elements and their occurences
unordered_map<int, int> map;
for (auto i:nums){
if(map.find(i) == map.end()) {
map.insert({i, 1});
} else {
map[i]++;
}
}
// now that we have all the counts we'll do a quick heap implementation
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> minHeap;
for (auto it=map.begin(); it!=map.end(); it++) {
minHeap.push({
it->second, it->first
});
if (minHeap.size() > k) {
minHeap.pop();
}
}
// at the end we have top k elements in the minHeap
vector<int> answer;
while(!minHeap.empty()) {
answer.push_back(minHeap.top().second);
minHeap.pop();
}
return answer;
}
};
K Closest Points to Origin
Find the problem on leetcode \(\to\)
Problem Statement
Given an array of points where \(\text{points(i)} = [x_i, y_i]\) represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0).
The distance between two points on the X-Y plane is the Euclidean distance (i.e., \(\sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}\))
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).
Approach
- We'll use max heap to store the distant points from the origin.
- To know how much distance they are in we'll make some ID system for each of the points, and calculate the distance between that point and the origin then put it in a hash table along with the ID,
- Now we'll for each entry in the hashtable we'll put the entry in a max heap (with priority being the distance to the origin), if the max heap size if greater than \(k\) then we'll pop from the heap,
- at last we'll get all the point's IDs remaining in the priority queue and return them via a ID to point lookup.
Code
class Solution {
public:
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
vector<int> origin = {0,1};
// make an ID System to identify each of the points
// let's say their index in the points array is their ID
// making map of point IDs and their distance to the origin
// ID -> distance map
unordered_map<int, float> distances;
for (int i=0; i<points.size(); i++) {
float distance = sqrt(points[i][0] * points[i][0] + points[i][1] * points[i][1]);
distances.insert({i, distance});
}
// now make a priority queue to store the order and at last find k closest points
// using a max heap we can do that
priority_queue<pair<float, int>> pq; // Max Heap
for (auto v:distances) {
int id = v.first;
int distance = v.second;
pq.push({v.second, v.first});
if (pq.size() > k) {
pq.pop();
}
}
// now the last k means the k closest points are remaining in the pq
vector<vector<int>> answers;
while (not pq.empty()) {
auto top = pq.top();
pq.pop();
vector<int> v = {points[top.second][0], points[top.second][1]};
answers.push_back(v);
}
return answers;
}
};
Comments
This comments system is powered by GitHub Discussions