Skip to content

Commit f95a370

Browse files
authored
Create README.md
1 parent e205334 commit f95a370

File tree

1 file changed

+152
-0
lines changed
  • 19 - Heap Data Structure Problems/03 - Kth Smallest

1 file changed

+152
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<h1 align='center'>Kth - Smallest</h1>
2+
3+
## Problem Statement
4+
**Problem URL :** [Kth Smallest](https://www.geeksforgeeks.org/problems/kth-smallest-element5635/1?itm_source=geeksforgeeks&itm_medium=article&itm_campaign=practice_card)
5+
6+
![image](https://github.com/user-attachments/assets/8a47a181-3af6-49e7-8e7e-695c2a8c3d22)
7+
8+
## Problem Explanation
9+
10+
The **Kth Smallest Element** problem requires us to find the `k`th smallest element in a given array. This is commonly encountered in coding interviews and is essential for learning how to handle selection problems in an array efficiently.
11+
12+
Let's break down what it means with an example:
13+
1. **Input**: We have an unsorted array `arr = [7, 10, 4, 3, 20, 15]` and we want to find the 3rd smallest element (`k = 3`).
14+
2. **Output**: The 3rd smallest element in this array is `7`, because if we sorted the array, we would get `[3, 4, 7, 10, 15, 20]`.
15+
16+
To solve this, the naive approach would be to sort the entire array and pick the `k`th element directly, but that could take time `O(n log n)` where `n` is the size of the array. However, we can use a more efficient solution using a **Max Heap** (or priority queue), which allows us to only keep track of the smallest `k` elements without fully sorting the array.
17+
18+
### Approach to Solve the Problem
19+
20+
1. **Max Heap Initialization**:
21+
- We initialize a **Max Heap** to store the smallest `k` elements seen so far. This is done because, in a Max Heap, the largest element among the smallest `k` elements will always be at the top.
22+
- In C++, the `priority_queue<int>` by default is a Max Heap.
23+
24+
2. **First `k` Elements**:
25+
- Push the first `k` elements of `arr` into the heap. After adding these `k` elements, the root of the heap (i.e., `pq.top()`) will contain the largest element among the first `k` elements.
26+
27+
3. **Traverse Remaining Elements**:
28+
- For each element from the `k+1`th element onwards:
29+
- If this element is smaller than the top of the Max Heap, remove the top element and insert the current element.
30+
- This step ensures that we always maintain only the `k` smallest elements in the heap, with the largest of them at the root.
31+
32+
4. **Result**:
33+
- Once all elements have been processed, the top of the Max Heap will contain the `k`th smallest element in the array.
34+
35+
## Problem Solution
36+
```cpp
37+
class Solution {
38+
public:
39+
// arr : given array
40+
// k : find kth smallest element and return using this function
41+
int kthSmallest(vector<int> &arr, int k) {
42+
priority_queue<int> pq;
43+
44+
for(int i = 0; i < k; i++){
45+
pq.push(arr[i]);
46+
}
47+
48+
for(int i = k; i < arr.size(); i++){
49+
if(arr[i] < pq.top()){
50+
pq.pop();
51+
pq.push(arr[i]);
52+
}
53+
}
54+
55+
return pq.top();
56+
}
57+
};
58+
```
59+
60+
## Problem Solution Explanation
61+
Here's a line-by-line breakdown of the code, including explanations for each part with examples.
62+
63+
```cpp
64+
class Solution {
65+
public:
66+
// arr : given array
67+
// k : find kth smallest element and return using this function
68+
int kthSmallest(vector<int> &arr, int k) {
69+
```
70+
71+
- We define a class `Solution` with a public method `kthSmallest`.
72+
- The method takes a reference to a vector `arr` (our input array) and an integer `k`, representing the position of the smallest element we want to find.
73+
- **Example**: If `arr = [7, 10, 4, 3, 20, 15]` and `k = 3`, our goal is to find the 3rd smallest element.
74+
75+
```cpp
76+
priority_queue<int> pq;
77+
```
78+
79+
- Here, we declare a max-heap `pq` using `priority_queue<int>` in C++. By default, `priority_queue` in C++ is a max-heap, which means the largest element will always be at the top.
80+
- This max-heap will help us keep track of the `k` smallest elements in the array.
81+
- **Example**: Initially, the max-heap is empty: `pq = {}`.
82+
83+
```cpp
84+
for(int i = 0; i < k; i++){
85+
pq.push(arr[i]);
86+
}
87+
```
88+
89+
- We push the first `k` elements of `arr` into the max-heap.
90+
- After this loop, the heap `pq` will contain the first `k` elements of `arr`, with the largest of these elements at the root/top of the heap.
91+
- **Example**: If `arr = [7, 10, 4, 3, 20, 15]` and `k = 3`, after this loop, the heap contains `{10, 7, 4}`, with `10` as the largest element at the top.
92+
93+
```cpp
94+
for(int i = k; i < arr.size(); i++){
95+
if(arr[i] < pq.top()){
96+
pq.pop();
97+
pq.push(arr[i]);
98+
}
99+
}
100+
```
101+
102+
- Now we iterate over the rest of the array, starting from index `k`.
103+
- `arr[i] < pq.top()`: We check if the current element of `arr` is smaller than the largest element in our heap (`pq.top()`).
104+
- If it is smaller, we pop the largest element from the heap (remove the root) and push the current element. This step ensures that we maintain only the `k` smallest elements in `pq`, with the largest of those `k` elements at the top.
105+
- If the current element is not smaller, we ignore it and move to the next one.
106+
- **Example**:
107+
- Let’s continue with `arr = [7, 10, 4, 3, 20, 15]` and `k = 3`.
108+
- Initially, `pq = {10, 7, 4}`.
109+
- For `arr[3] = 3`: `3 < 10` (top of heap), so we pop `10` and push `3`. Now, `pq = {7, 4, 3}`.
110+
- For `arr[4] = 20`: `20 > 7` (top of heap), so we ignore it.
111+
- For `arr[5] = 15`: `15 > 7` (top of heap), so we ignore it.
112+
113+
```cpp
114+
return pq.top();
115+
}
116+
};
117+
```
118+
119+
- After processing all elements, the top of the heap (`pq.top()`) holds the `k`th smallest element.
120+
- **Example**: In our example, `pq.top()` is `7`, so `7` is the 3rd smallest element in `arr = [7, 10, 4, 3, 20, 15]`.
121+
122+
### Full Example Walkthrough
123+
124+
For `arr = [7, 10, 4, 3, 20, 15]` and `k = 3`:
125+
1. **Initialize Heap**:
126+
- Insert first `k` elements `[7, 10, 4]` into `pq`.
127+
- `pq = {10, 7, 4}`, with `10` as the max (top of heap).
128+
129+
2. **Process Remaining Elements**:
130+
- `3 < 10`: Pop `10`, push `3``pq = {7, 4, 3}`.
131+
- `20 > 7`: Ignore it.
132+
- `15 > 7`: Ignore it.
133+
134+
3. **Result**:
135+
- `pq.top()` is `7`, which is the 3rd smallest element in `arr`.
136+
137+
### Step 4: Time and Space Complexity
138+
139+
1. **Time Complexity**:
140+
- Building the initial Max Heap with `k` elements takes `O(k log k)`.
141+
- For the remaining `n - k` elements, each comparison and insertion takes `O(log k)`, leading to an overall complexity of `O(k log k) + O((n - k) log k)`, which simplifies to `O(n log k)`.
142+
143+
2. **Space Complexity**:
144+
- The space complexity is `O(k)` due to the Max Heap storing up to `k` elements.
145+
146+
### Step 5: Additional Recommendations for Students
147+
148+
- **Heap Fundamentals**: Understanding how heaps work and when to use Max vs. Min Heaps is critical for similar problems.
149+
- **Edge Cases**: Consider cases where `k` is `1` (smallest element) or equal to the array's length (largest element).
150+
- **Alternative Approaches**: For large values of `k`, a Min Heap might be a better choice, or use quickselect for linear-time average solutions.
151+
152+
This approach using a Max Heap is efficient and aligns well with real-world problem-solving needs where we handle partial sorts frequently.

0 commit comments

Comments
 (0)