Heap / Priority Queue
Expert Answer & Key Takeaways
Heap and Priority Queue Mental Models
1. Types of Heaps
- Max-Heap: The value of the root node must be the greatest among all its children. The same property must be recursively true for all subtrees.
- Min-Heap: The value of the root node must be the smallest among all its children.
2. Binary Heap Structure (Array Representation)
i:- Parent:
(i - 1) / 2 - Left Child:
2 * i + 1 - Right Child:
2 * i + 2
3. Core Operations (Time Complexity)
| Operation | Description | Time Complexity |
|---|---|---|
| Insert | Add an element and Sift-Up | |
| Extract Min/Max | Remove root and Sift-Down | |
| Peek | View root value | |
| Heapify | Create heap from array |
4. Visualizing Sift-Up (Insertion)
Initial Max-Heap: [10, 8, 5]
Insert 15:
1. [10, 8, 5, 15] (Add at end)
2. [10, 15, 5, 8] (Swap 15 with 8, 15 > 8)
3. [15, 10, 5, 8] (Swap 15 with 10, 15 > 10)
Done: Root is 15.5. Common Use Cases
- Top K Elements: Use a heap of size K ().
- Merging Sorted Streams: K-way merge ().
- Dijkstra's / Prim's Algorithms: Finding shortest paths/MST.
Top K Frequent Elements
nums and an integer k, return the k most frequent elements. You may return the answer in any order.Visual Representation
nums = [1, 1, 1, 2, 2, 3], k = 2
Frequency Count Buckets:
0: []
1: [3] (val 3 appears 1 time)
2: [2] (val 2 appears 2 times)
3: [1] (val 1 appears 3 times)
4: []
5: []
6: []
Iterate buckets from right to left:
Bucket 3 -> [1]
Bucket 2 -> [2]
Result (k=2): [1, 2]Examples
Level I: Sorting (Naive)
Intuition
k elements.Thought Process
- Use a Hash Map to count occurrences.
- Create a list of pairs
(element, frequency). - Sort the list by frequency in descending order.
- Take the top
kelements.
Detailed Dry Run
- Map: {1: 2, 2: 1}
- Pairs: [(1, 2), (2, 1)]
- Sorted: [(1, 2), (2, 1)]
- result: [1]
Level II: Bucket Sort (Optimal)
Intuition
bucket[i] stores elements that appear times. Iterate from down to 1.Thought Process
- Count frequencies with a Map.
- Create an array of lists
bucketsof size . - Place each element in its corresponding frequency bucket.
- Traverse buckets from right to left to collect top elements.
Detailed Dry Run
- Map: {1:3, 2:2, 3:1}
- Buckets: [[], [3], [2], [1], [], [], []]
- Bucket 3: adds [1]. Result [1]
- Bucket 2: adds [2]. Result [1, 2]. Done.
Level III: Min-Heap (Optimal)
Intuition
k. If the size exceeds k, we pop the element with the smallest frequency. At the end, the heap contains the k most frequent elements.Thought Process
- Count frequencies using a Map.
- Iterate through unique elements and push them into a Min-Heap based on frequency.
- If heap size >
k, pop from heap. - The remaining elements in the heap are the result.
Detailed Dry Run
- Map: {1:3, 2:2, 3:1}
- Push 1 (freq 3): Heap [(1,3)]
- Push 2 (freq 2): Heap [(2,2), (1,3)]
- Push 3 (freq 1): Heap [(3,1), (2,2), (1,3)] -> Size 3 > k, Pop (3,1). Final Heap: [(2,2), (1,3)] -> Result [1, 2]
Kth Largest Element in an Array
nums and an integer k, return the kth largest element in the array.kth largest element in the sorted order, not the kth distinct element.Visual Representation
nums = [3,2,1,5,6,4], k = 2
Min-Heap (size k=2):
[1] -> [1, 2] -> [2, 3] -> [3, 5] -> [5, 6] -> [5, 6] (after 4)
Heap top is 5th largest.
Quickselect (Partitions):
[3, 2, 1, 5, 6, 4] -> pivot 4
[3, 2, 1] | [4] | [5, 6]
Target index is in the right partition.Examples
Level I: Sorting (Naive)
Intuition
k-1.Thought Process
- Sort the input array.
- Access the element at
length - k(for ascending sort) ork - 1(for descending sort).
Detailed Dry Run
- Sorted: [1, 2, 2, 3, 3, 4, 5, 5, 6]
- Index (9 - 4) = 5
- nums[5] = 4
Level II: Quickselect (Average Case Optimal)
Intuition
Thought Process
- Choose a pivot element.
- Partition the array around the pivot like in Quicksort.
- Compare the pivot's final index with target index .
- Recurse into the sub-array containing the target index.
Detailed Dry Run
- Partition: [3, 2, 1, 4, 6, 5], 4 is at index 3.
- 3 < 4: Recurse [6, 5]
- Partition: [5, 6], 6 is at index 5.
- 5 > 4: Recurse [5]
- Index 4 is 5. Return 5.
Level III: Min-Heap (Optimal)
Intuition
k. As we iterate through the array, if we find an element larger than the heap's minimum, we replace the minimum with it. After one pass, the heap contains the k largest elements, and the top is the kth largest.Thought Process
- Initialize a Min-Heap.
- For each number in
nums:- Push to heap.
- If heap size >
k, pop the smallest element.
- The root of the heap is our answer.
Detailed Dry Run
- Push 3: Heap [3]
- Push 2: Heap [2, 3]
- Push 1: Heap [1, 2, 3] -> Pop 1. Heap [2, 3]
- Push 5: Heap [2, 3, 5] -> Pop 2. Heap [3, 5]
- Push 6: Heap [3, 5, 6] -> Pop 3. Heap [5, 6]
- Push 4: Heap [4, 5, 6] -> Pop 4. Heap [5, 6] Result: Top is 5
Task Scheduler
tasks, representing the tasks a CPU needs to do, where each letter represents a different task. Tasks can be done in any order. Each task is done in one unit of time. For each unit of time, the CPU could complete either one task or just be idle.n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of time between any two same tasks.Visual Representation
tasks = [A, A, A, B, B, B], n = 2
Simulation Steps:
1. A (freq 3->2) | Waitlist: [(A, T=3)]
2. B (freq 3->2) | Waitlist: [(A, T=3), (B, T=4)]
3. IDLE | Waitlist: [(A, T=3), (B, T=4)]
4. A (freq 2->1) | A returns from waitlist at T=3
...
Result: A B IDLE A B IDLE A B = 8 unitsExamples
Level I: Max-Heap + Cooling Queue (Simulation)
Intuition
Thought Process
- Count frequency of each task.
- Push frequencies into a Max-Heap.
- While heap or cooldown queue is not empty:
- Increment time.
- If heap has tasks, take the most frequent, decrement its count, and if count > 0, add to queue with its 'available time'.
- If queue has a task whose cooldown is over, push it back to the heap.
Detailed Dry Run
- Heap: [A:3, B:3], Queue: [], Time: 0
- Time 1: Process A. Heap [B:3], Queue [(A:2, T=4)]
- Time 2: Process B. Heap [], Queue [(A:2, T=4), (B:2, T=5)]
- Time 3: Idle. Queue is cool until T=4.
- Time 4: Q.pop A. Heap [A:2]... and so on until 8.
Level II: Greedy (Simplified Priority Queue)
Intuition
Thought Process
- Count frequencies.
- Use a Priority Queue (Max-Heap).
- In each chunk of time units, pick tasks from heap.
- If heap is empty but we still have tasks to process (temporarily removed), add 'idle' counts.
Detailed Dry Run
- Frequencies: {A:3, B:3}
- Iteration 1: Chunk size 3. Pick A (rem 2), B (rem 2). Total time 2. Remaining tasks exist, so add 1 idle. Time 3.
- Iteration 2: Pick A (rem 1), B (rem 1). Time 6.
- Iteration 3: Pick A (rem 0), B (rem 0). Time 8. Done.
Level III: Greedy (Mathematical)
Intuition
maxFreq. There are maxFreq - 1 gaps between these tasks, each of size n. We fill these gaps with other tasks. If the total units required is less than the total number of tasks, the answer is the total tasks.Formula
partCount = maxFreq - 1
partLength = n - (countOfTasksWithMaxFreq - 1)
emptySlots = partCount * partLength
availableTasks = tasks.length - maxFreq * countOfTasksWithMaxFreq
idles = max(0, emptySlots - availableTasks)
Result = tasks.length + idlesDetailed Dry Run
- maxFreq = 3 (A and B both have 3).
- Max freq task count = 2 (A and B).
- Formula: (3-1) * (2+1) + 2 = 8. Total Time = 8.
K Closest Points to Origin
points where points[i] = [xi, yi] represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0).Visual Representation
points = [[1,3],[-2,2]], k = 1
Distance of [1,3] = sqrt(1^2 + 3^2) = sqrt(10) ≈ 3.16
Distance of [-2,2] = sqrt((-2)^2 + 2^2) = sqrt(8) ≈ 2.83
Closest Point: [-2, 2]Examples
Level I: Sorting (Naive)
Intuition
k points.Thought Process
- Use a custom comparator to compare points and based on vs .
- Sort the array using this comparator.
- Return the sub-array of size
k.
Detailed Dry Run
- Dist sq: [10, 8]
- Sorted by dist: [[-2,2], [1,3]]
- Take first k=1: [[-2,2]]
Level II: Quickselect (Average Case Optimal)
Intuition
Thought Process
- Define distance function .
- Partition the points based on .
- If pivot index equals , all points to the left are the closest.
- Recurse into the necessary partition.
Detailed Dry Run
- Partition around pivot 20: [[3,3], [-2,4], [5,-1]]. Pivot 20 is at index 1.
- k=2, so we need to ensure index 1 is part of the result. Return points[0...1].
Level III: Max-Heap (Optimal)
Intuition
k to store the points with the smallest distances. If we find a point with a smaller distance than the maximum in our heap, we replace the maximum with it.Thought Process
- Initialize a Max-Heap based on squared Euclidean distance.
- Iterate through all
points. - Push the current point into the heap.
- If heap size >
k, pop the point with the largest distance (the root). - After all points are processed, the heap contains the
kclosest points.
Detailed Dry Run
- Point [3,3], Dist 18: Heap [[3,3] (Dist 18)]
- Point [5,-1], Dist 26: Heap [[5,-1] (Dist 26), [3,3] (Dist 18)]
- Point [-2,4], Dist 20: Heap [[5,-1] (Dist 26), [-2,4], [3,3]] -> Pop [5,-1]. Final Heap: [[-2,4], [3,3]]
Meeting Rooms II
intervals where intervals[i] = [starti, endi], return the minimum number of conference rooms required.Visual Representation
intervals = [[0,30],[5,10],[15,20]]
Timeline:
0 5 10 15 20 30
|--|---|---|----|----|
[0 30] (Room 1)
[5 10] (Room 2)
[15 20] (Room 2 - reused)
Max overlapping at any time: 2Examples
Level I: Min-Heap (Interval Management)
Intuition
Thought Process
- Sort
intervalsby start time. - Initialize a Min-Heap to store end times.
- For each interval:
- If heap is not empty and
heap.peek() <= current.start, pop the heap (room becomes free). - Push current interval's end time to heap.
- If heap is not empty and
- The final size of the heap is the number of rooms needed.
Detailed Dry Run
- Sorted: [[0,30],[5,10],[15,20]]
- Int [0,30]: Heap [30]
- Int [5,10]: Heap.peek(30) > 5. Push 10. Heap [10, 30]
- Int [15,20]: Heap.peek(10) <= 15. Pop 10. Push 20. Heap [20, 30] Result: Heap size = 2
Level II: Sweep Line (Difference Array Logic)
Intuition
Thought Process
- For each interval , create two points: and .
- Sort todos points by time.
- If times are equal, process end events before start events if the interval is exclusive, OR start before end if inclusive. (LeetCode meetings are inclusive of start, exclusive of end, so end before start at same time).
- Traverse through sorted points and maintain a running sum.
Detailed Dry Run
- Events: (0,+1), (30,-1), (5,+1), (10,-1), (15,+1), (20,-1)
- Sorted: (0,+1), (5,+1), (10,-1), (15,+1), (20,-1), (30,-1)
- Sums: 1 -> 2 -> 1 -> 2 -> 1 -> 0 Max Sum: 2
Level III: Two Pointers (Chronological Ordering)
Intuition
Logic Steps
- Extract all
startsandendsinto separate arrays. - Sort both arrays.
- Use two pointers
sande. - If
starts[s] < ends[e], incrementusedRoomsands. - Else (room freed), increment
eands(total rooms stays same).
Detailed Dry Run
- s=0, e=0: starts[0]=0 < ends[0]=10 -> rooms=1, s=1
- s=1, e=0: starts[1]=5 < ends[0]=10 -> rooms=2, s=2
- s=2, e=0: starts[2]=15 >= ends[0]=10 -> rooms=2, e=1, s=3 Result: 2 rooms.
Rearrange String k Distance Apart
s and an integer k, rearrange s such that the same characters are at least distance k from each other. If it is not possible to rearrange the string, return an empty string "".Visual Representation
s = "aabbcc", k = 3
Frequency Count:
a: 2, b: 2, c: 2
Step-by-Step Selection (k=3):
Pos 0: Use 'a' (freq 2->1) | Wait: {a: wait 2}
Pos 1: Use 'b' (freq 2->1) | Wait: {a: wait 1, b: wait 2}
Pos 2: Use 'c' (freq 2->1) | Wait: {a: wait 0, b: wait 1, c: wait 2}
Pos 3: 'a' is free! Use 'a'| Wait: {b: wait 0, c: wait 1, a: wait 2}
...
Result: "abcabc"Examples
Level I: Greedy with Max-Heap (Standard)
Intuition
k-1 positions. Use a Max-Heap to track frequencies and a queue to manage the 'waitlist'.Thought Process
- Count frequency of each character.
- Push char-frequency pairs into a Max-Heap.
- While heap is not empty:
- Extract the character with the max frequency.
- Append it to the result.
- Decrement its frequency.
- Add it to a 'waitlist' queue.
- If the waitlist queue size reaches
k, pop the character from the front and push it back into the heap (if its freq > 0).
Detailed Dry Run
- Map: {a:3, b:1, c:1}, Heap: [a:3, b:1, c:1], Wait: []
- Step 1: Use 'a'. Result: "a", Heap: [b:1, c:1], Wait: [(a, 2)]
- Step 2: Use 'b'. Result: "ab", Heap: [c:1], Wait: [(a, 2), (b, 0)]
- Step 3: Use 'c'. Result: "abc", Heap: [], Wait: [(a, 2), (b, 0), (c, 0)]
- Wait size 3: Push 'a' back to heap. Heap: [a:2]
- Continue... (If result length != s length, return "")
Level II: Greedy with Alphabet Array (O(N * 26))
Intuition
Detailed Dry Run
- Freqs: {a:2, b:2, c:2}, LastPos: {a:-inf, b:-inf, c:-inf}
- Pos 0: 'a' is valid and max freq. Res: "a", Freqs: {a:1...}, LastPos: {a:0}
- Pos 1: 'a' invalid (1 < 3), 'b' is valid and max freq. Res: "ab"...
- Pos 3: 'a' becomes valid again (3-0 >= 3).
Level III: Optimal (Modified Greedy with Max-Freq Limit Check)
Intuition
Detailed Dry Run
- Freqs: {a:3, b:1, c:1}. Heap: [a:3, b:1, c:1]. Wait: []
- Pop 'a'. Res: "a". Freq: a:2. Wait: [a:2].
- Wait size < 3. Continue.
- If heap empty and res.length < s.length, return "".
Find K Pairs with Smallest Sums
nums1 and nums2 sorted in non-decreasing order and an integer k.(u, v) which consists of one element from nums1 and one element from nums2.k pairs (u1, v1), (u2, v2), ..., (uk, vk) with the smallest sums.Visual Representation
nums1 = [1, 7, 11], nums2 = [2, 4, 6], k = 3
Possible Pairs:
(1,2) sum=3
(1,4) sum=5
(1,6) sum=7
(7,2) sum=9 ...
Smallest 3 pairs: [[1,2], [1,4], [1,6]]Examples
Level I: Brute Force + Sorting
Intuition
k pairs.Thought Process
- Nest two loops to iterate over
nums1andnums2. - Store each pair and its sum in a list.
- Sort the list by sum.
- Take the first
kelements.
Detailed Dry Run
- Pairs: [[1,3] sum:4, [2,3] sum:5]
- Sorted: [[1,3], [2,3]]
- Result: [[1,3]]
Level II: Max-Heap of size K (Better Brute Force)
Intuition
Thought Process
- Use a Max-Heap to store
[u, v]pairs based on their sum. - Iterate through
nums1andnums2(limit to to avoid unnecessary checks). - Push each pair to the heap.
- If heap size exceeds , pop the largest (root).
- Return all pairs in the heap.
Detailed Dry Run
- Pair [1,3], sum 4. Heap: [[1,3]]
- Pair [2,3], sum 5. Heap: [[2,3], [1,3]] -> Pop [2,3]. Heap: [[1,3]] Result: [[1,3]]
Level III: Min-Heap (Optimal)
Intuition
(nums1[0], nums2[0]). The next candidates are (nums1[1], nums2[0]) or (nums1[0], nums2[1]). We can use a Min-Heap to explore pairs efficiently.Thought Process
- Push
(nums1[i], nums2[0], 0)for alli(or justi=0and expand both ways) into a Min-Heap. - In each step, pop the smallest pair
(nums1[i], nums2[j]). - Add it to result.
- Push the next potential pair
(nums1[i], nums2[j+1])into the heap. - Repeat
ktimes.
Detailed Dry Run
- Heap: [(1,2,idx_in_nums2=0)]
- Pop (1,2). Result: [[1,2]]. Push next in nums2: (1,4,1). Heap: [(1,4,1)]
- Pop (1,4). Result: [[1,2],[1,4]]. Push next: (1,6,2). Heap: [(1,6,2), (7,2,0)] (Note: 7,2 is pushed later or initialized) Actually simpler: Push all nums1[i] + nums2[0].
- Heap: [(1+2, 0,0), (7+2, 1,0), (11+2, 2,0)]
- Pop (3, 0,0). Result [[1,2]]. Push (1+4, 0,1).
- Pop (5, 0,1). Result [[1,2], [1,4]]. Push (1+6, 0,2).
- Pop (7, 0,2). Result [[1,2], [1,4], [1,6]]. Done.
Sort Characters By Frequency
s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.Visual Representation
s = "tree"
Frequency Count:
'e': 2
't': 1
'r': 1
Sorted by frequency: 'e' -> 't' -> 'r'
Result: "eetr" or "eert"Examples
Level I: Max-Heap (Standard)
Intuition
Thought Process
- Use a hash map to count character frequencies.
- Add all
(frequency, character)pairs to a Max-Heap. - Poll characters from the heap and append each to a
StringBuilderfrequencytimes. - Return the constructed string.
Detailed Dry Run
- Map: {'t':1, 'r':1, 'e':2}
- Max-Heap: [('e',2), ('t',1), ('r',1)]
- Pop ('e',2). Appended 2 times -> "ee"
- Pop ('t',1). Appended 1 time -> "eet"
- Pop ('r',1). Appended 1 time -> "eetr" Result: "eetr"
Level II: Sorting Map Entries
Intuition
Detailed Dry Run
- Map: {'t':1, 'r':1, 'e':2}
- List of entries: [('t',1), ('r',1), ('e',2)]
- Sorted List: [('e',2), ('t',1), ('r',1)]
- Result: "eetr"
Level III: Bucket Sort (Optimal)
Intuition
N, we can use an array of lists as buckets. bucket[i] stores characters that appear exactly i times.Detailed Dry Run
- Map: {'t':1, 'r':1, 'e':2}
- Buckets array of size 5: [0:[], 1:['t','r'], 2:['e'], 3:[], 4:[]]
- Iterate from 4 down to 1.
- i=2: bucket contains 'e'. Append 'e' 2 times -> "ee"
- i=1: bucket contains 't','r'. Append 't' 1 time, 'r' 1 time -> "eetr"
Minimum Cost to Connect Sticks
sticks, where sticks[i] is the length of the ith stick.x and y into one stick by paying a cost of x + y. You must connect until there is only one stick remaining.Visual Representation
sticks = [2,4,3]
Options:
1. Connect 2 and 3: cost = 5, sticks = [4, 5]
Connect 4 and 5: cost = 9, sticks = [9]
Total cost: 5 + 9 = 14 (Optimal)
2. Connect 4 and 3: cost = 7, sticks = [2, 7]
Connect 2 and 7: cost = 9, sticks = [9]
Total cost: 7 + 9 = 16 (Not Optimal)Examples
Level I: Sorting Repeatedly (Simulation)
Intuition
Thought Process
- If
sticks.length <= 1, cost is 0. - Loop while we have more than 1 stick.
- Sort the array/list.
- Take the first two elements and add them to get
currentCost. - Add
currentCosttototalCost. - Remove the first two elements and insert
currentCost. - Repeat until 1 stick remains.
Detailed Dry Run
- Sort: [1, 3, 5, 8]
- Take 1, 3. Sum = 4. Cost = 4. Array [4, 5, 8]
- Sort: [4, 5, 8]
- Take 4, 5. Sum = 9. Cost = 4 + 9 = 13. Array [9, 8]
- Sort: [8, 9]
- Take 8, 9. Sum = 17. Cost = 13 + 17 = 30. Total = 30.
Level II: Binary Search Insertion (Optimized Simulation)
Intuition
Detailed Dry Run
- Sort: [1, 3, 5, 8]
- 1+3=4. Binary search 4 in [5, 8] -> index 0. List: [4, 5, 8].
- 4+5=9. Binary search 9 in [8] -> index 1. List: [8, 9].
- 8+9=17. Total: 4+9+17=30.
Level III: Min-Heap (Optimal)
Intuition
Thought Process
- Push all stick lengths into a Min-Heap.
- While the heap contains more than one stick:
- Extract the two smallest sticks (
s1,s2). - Calculate their sum (
cost = s1 + s2). - Add
costto thetotalCost. - Push the new combined stick (
cost) back into the heap.
- Extract the two smallest sticks (
- Once only one stick remains in the heap, return
totalCost.
Detailed Dry Run
- Heap: [1, 3, 5, 8], Cost: 0
- Pop 1, 3. Sum = 4. Cost = 4. Push 4. Heap: [4, 5, 8]
- Pop 4, 5. Sum = 9. Cost = 4 + 9 = 13. Push 9. Heap: [8, 9]
- Pop 8, 9. Sum = 17. Cost = 13 + 17 = 30. Push 17. Heap: [17]
- One element left. Return 30.
Find Median from Data Stream
MedianFinder class:MedianFinder()initializes theMedianFinderobject.void addNum(int num)adds the integernumfrom the data stream to the data structure.double findMedian()returns the median of all elements so far. Answers within10^-5of the actual answer will be accepted.
Visual Representation
Stream: [2, 3, 4]
addNum(2) -> [2] (Median = 2.0)
addNum(3) -> [2, 3] (Median = (2+3)/2 = 2.5)
addNum(4) -> [2, 3, 4] (Median = 3.0)
Two Heaps State:
Lower (Max-Heap) | Upper (Min-Heap)
[2] | []
[2] | [3]
[2, 3](pop->[2]) | [3, 4](push 3)
[2, 3] | [4]Examples
Level I: Array and Insertion Sort
Intuition
Thought Process
- Store numbers in a standard list or array.
- On
addNum(n):- Find the correct position to insert
nso the collection remains sorted. - Insert
n.
- Find the correct position to insert
- On
findMedian():- If the size is odd, return
list[size / 2]. - If the size is even, return
(list[size / 2 - 1] + list[size / 2]) / 2.0.
- If the size is odd, return
Detailed Dry Run
- add(1): Array = [1]
- add(2): Insert 2. Array = [1, 2]
- find(): Even size 2. Return (1+2)/2.0 = 1.5
- add(3): Insert 3. Array = [1, 2, 3]
- find(): Odd size 3. Middle is index 1. Return 2.0
Level II: TreeMap of Counts
Intuition
Detailed Dry Run
- add(1): map={1:1}, total=1
- add(2): map={1:1, 2:1}, total=2
- find(): total=2. Median is at pos 1, 2. Summing counts: at 1, count=1(pos 0-0), at 2, count=1(pos 1-1). Avg of 1 and 2 is 1.5.
- add(3): map={1:1, 2:1, 3:1}, total=3
- find(): total=3. Median is at pos 1. Summing: pos 1 is val 2. Return 2.0
Level III: Two Heaps (Optimal)
Intuition
Thought Process
low: A Max-Heap to store the smaller half of the numbers.high: A Min-Heap to store the larger half of the numbers.- When adding
num:- Always push to
low, then pop the largest fromlowand push it tohigh(to ensure every element inlowis smaller than elements inhigh). - Balance the heaps: If
highhas more elements thanlow, pophighand push tolow.
- Always push to
- When finding median:
- If sizes are unequal, the extra element is in
low, so return the top oflow. - If equal, return
(low.top() + high.top()) / 2.0.
- If sizes are unequal, the extra element is in
Detailed Dry Run
- Add 1: Push to low -> low=[1]. Pop low (1) -> Push to high. high=[1]. high size(1) > low size(0) -> Pop high(1) -> push to low. low=[1], high=[].
- Add 2: Push to low -> low=[2,1]. Pop low(2) -> push to high. high=[2], low=[1]. Sizes equal.
- Median: (1 + 2)/2.0 = 1.5
- Add 3: Push to low -> low=[3,1]. Pop low(3) -> push to high. high=[2,3], low=[1]. high size(2) > low size(1) -> Pop high(2) -> push to low. low=[2,1], high=[3].
- Median: low has extra. Return 2.0.
Sliding Window Maximum
nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.Visual Representation
nums = [1,3,-1,-3,5,3,6,7], k = 3
Window position Max
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7Examples
Level I: Max-Heap (Lazy Removal)
Intuition
O(N). Instead, we can use lazy removal: we store (value, index) in the heap. We only remove elements from the top of the heap if their index is outside the current window's bounds.Thought Process
- Use a Max-Heap storing pairs of
(nums[i], i). - Initialize the heap with the first
kelements. - The max of the first window is the top of the heap.
- Slide the window from
i = ktoN - 1:- Push
(nums[i], i)into the heap. - Check the top of the heap. If its index is
<= i - k, it means it's outside the window. Pop it. - Keep popping until the top is inside the window.
- Record the top's value as the max for the current window.
- Push
Detailed Dry Run
- Init k=3: Heap = [(3,1), (1,0), (-1,2)]. Max = 3.
- i=3 (val=-3): Push (-3,3). Heap = [(3,1), (1,0), (-1,2), (-3,3)]. Top idx=1 is inside window (3-3=0, 1>0). Max = 3.
- i=4 (val=5): Push (5,4). Heap = [(5,4), (3,1),...]. Top idx=4 is inside. Max = 5.
- i=5 (val=3): Push (3,5). Heap = [(5,4), ...]. Top idx=4 is inside. Max = 5.
Level II: Balanced BST / Sorted List
Intuition
Detailed Dry Run
- Initial window [1, 3, -1]. Sorted: [-1, 1, 3]. Max = 3.
- Slide to [3, -1, -3]: Remove 1, Insert -3. Sorted: [-3, -1, 3]. Max = 3.
- Slide to [-1, -3, 5]: Remove 3, Insert 5. Sorted: [-3, -1, 5]. Max = 5.
Level III: Monotonic Deque (Optimal)
Intuition
[5, 4, 2], the maximum is 5. If we add a new number 6, then 5, 4, 2 are completely useless because they are smaller than 6 and will leave the window before 6 does! Thus, a monotonically decreasing deque can perfectly track the useful candidates for being the window's max.Thought Process
- Maintain a deque (double-ended queue) of
indices. - The elements represented by indices in the deque are kept in strictly descending order.
- Loop over
nums[i]from0toN-1:- Maintain Window Bound: If the index at the
frontof the deque is out of the current window (< i - k + 1), remove it from the front. - Maintain Descending Order: While the deque is not empty and the element at the
backis< nums[i], remove it from the back. (They are useless now). - Add current index
ito the back. - Once
i >= k - 1, the window is fully formed. The maximum is always at thefrontof the deque, so appendnums[deque.front()]to the result.
- Maintain Window Bound: If the index at the
Detailed Dry Run
- i=0, v=1: dq=[0 (val:1)]
- i=1, v=3: 1 < 3, pop 0. dq=[1 (val:3)]
- i=2, v=-1: -1 < 3, keep. dq=[1, 2]. Window full, max=nums[1]=3
- i=3, v=-3: -3 < -1, keep. dq=[1, 2, 3]. max=nums[1]=3
- i=4, v=5: front 1 out of bounds (1 <= 4-3). pop 1. val 5 > -1, -3. pop 2, 3. push 4. dq=[4 (val:5)]. max=5
Trapping Rain Water II
m x n integer matrix heightMap representing the height of each unit cell in a 2D elevation map, return the volume of water it can trap after raining.Visual Representation
heightMap =
[1, 4, 3, 1, 3, 2]
[3, 2, 1, 3, 2, 4]
[2, 3, 3, 2, 3, 1]
Water trapped at (1,1) (height 2): bounded by 3, 4, 3, 3. Can hold 1 unit.
Water trapped at (1,2) (height 1): bounded by 3, 2, 3, 3. Can hold 2 units.
Total trapped = 14 units.
Min-Heap expanding from boundaries:
Push all boundary cells to Min-Heap.
Always pop the lowest boundary (weakest link) to see if water can flow into its neighbors.Examples
Level I: Iterative Water Level Updates
Intuition
(r, c) is determined by the maximum of its own height and the minimum water level of its neighbors. We can start by assuming every inner cell can hold infinite water, and boundary cells hold exactly their height. Then, we iteratively relax (update) the inner cells until the water levels stabilize (no more changes occur), similar to the Bellman-Ford algorithm.Detailed Dry Run
Level II: 4-Way Boundary Scanning (Upper Bound Heuristic)
Intuition
min(maxLeft, maxRight). We can extend this logic to 2D by calculating the maximum height seen from all four cardinal directions (Left, Right, Top, Bottom) for each cell. The water level at (r, c) can be at most the minimum of these four peaks. While this ignores diagonal leaks, it provides an heuristic that is faster than iterative relaxation.Detailed Dry Run
- MaxLeft = 3, MaxRight = 3, MaxUp = 3, MaxDown = 3
- Level = min(3,3,3,3) = 3
- Trapped = 3 - 1 = 2 (Correct in this case).
Level III: Min-Heap + BFS (Optimal)
Intuition
Detailed Dry Run
- Push all boundaries to Min-Heap: (3,0,0),(3,0,1)... Visited boundary.
- Pop (3,0,1). Check neighbor (1,1). It's unvisited. Height is 1.
- Inner height 1 < Boundary height 3. Trapped = 3 - 1 = 2.
- Push neighbor (1,1) into Heap with updated height
max(1, 3) = 3, mark visited. - Continue popping. Other neighbors of (1,1) are boundaries and visited. Return total trapped = 2.
Minimum Cost to Hire K Workers
n workers. You are given two integer arrays quality and wage where quality[i] is the quality of the ith worker and wage[i] is the minimum wage expectation for the ith worker.k workers to form a paid group. To hire a group of k workers, we must pay them according to the following rules:- Every worker in the paid group should be paid in the ratio of their quality compared to other workers in the paid group.
- Every worker in the paid group must be paid at least their minimum wage expectation.
Visual Representation
quality = [10, 20, 5], wage = [70, 50, 30], k = 2
Ratios (wage/quality):
Worker 0: 70/10 = 7.0
Worker 1: 50/20 = 2.5
Worker 2: 30/5 = 6.0
Sorted by ratio:
[W1(2.5, q:20), W2(6.0, q:5), W0(7.0, q:10)]
To hire W2 and W1, base ratio is 6.0.
Cost = 6.0 * (20 + 5) = 150.0
To hire W0 and W2, base ratio is 7.0.
Cost = 7.0 * (10 + 5) = 105.0
Min cost = 105.0Examples
Level I: Sort by Ratio and Brute Force K-Smallest
Intuition
K workers is determined by the highest wage / quality ratio among the chosen K workers. If we sort workers by this ratio, when we consider the i-th worker in the sorted list as having the maximum ratio, any K-1 workers before i can be hired at this ratio. To minimize cost, we should simply pick the K-1 workers with the smallest qualities from 0 to i-1.Thought Process
- Pair each worker's quality with their
wage/qualityratio. - Sort all workers by their ratio in ascending order.
- Iterate
ifromk - 1ton - 1(a valid window to pickkworkers). - For each
i, the ratio isworker[i].ratio. - We need to pick
kqualities from index0toi(includingworker[i].quality) that are the smallest. Sinceworker[i]must be included, we pickworker[i].quality+k-1smallest qualities from0toi-1. - For a brute force approach, extract all qualities from
0toi, sort them, sum the firstk, and multiply by the ratio. - Keep track of the minimum cost.
Detailed Dry Run
- i=1 (ratio=6.0, q=5). We need 2 qualities from idx 0 to 1. Qualities: [20, 5]. Sorted: [5, 20]. Sum = 25. Cost = 6.0 * 25 = 150.0. Min = 150.0
- i=2 (ratio=7.0, q=10). We need 2 qualities from idx 0 to 2. Qualities: [20, 5, 10]. Sorted: [5, 10, 20]. Sum = 5 + 10 = 15. Cost = 7.0 * 15 = 105.0. Min = 105.0
Level II: Sort by Ratio + BST/TreeMap for Qualities
Intuition
Detailed Dry Run
- i=1 (ratio=6.0, q=5): BST = {5, 20}. Sum of 2 smallest = 25. Cost = 6.0 * 25 = 150.0.
- i=2 (ratio=7.0, q=10): BST = {5, 10, 20}. Sum of 2 smallest = 15. Cost = 7.0 * 15 = 105.0.
Level III: Max-Heap (Optimal)
Intuition
K smallest qualities seen so far. As we iterate through the workers sorted by ratio, we can maintain a Max-Heap of size K. If we add a new quality and the heap size exceeds K, we pop the maximum quality out. This seamlessly keeps track of the sum of the K smallest qualities in O(log K) time per worker.Detailed Dry Run
pq, quality_sum = 0- i=0, (2.5, 20): push 20. pq=[20], sum=20. size 1 < 2. Cost: ignore.
- i=1, (6.0, 5): push 5. pq=[20,5], sum=25. size 2 == 2. Cost = 25 * 6.0 = 150.0. Min = 150.0
- i=2, (7.0, 10): push 10. sum=35. pq=[20,10,5]. size 3 > 2 -> pop max (20). sum = 35 - 20 = 15. Size is now 2. Cost = 15 * 7.0 = 105.0. Min = min(150, 105) = 105.0. Return 105.0
IPO
k distinct projects before the IPO. Help LeetCode design the best way to maximize its total capital after finishing at most k distinct projects.n projects where the ith project has a pure profit profits[i] and a minimum capital of capital[i] is needed to start it.w capital. When you finish a project, you will obtain its pure profit and the profit will be added to your total capital. Return the maximized final capital.Visual Representation
k = 2, w = 0, profits = [1, 2, 3], capital = [0, 1, 1]
Initial Capital w = 0
Available Projects (capital <= 0): Project 0 (profit 1)
Do Project 0 -> w = 0 + 1 = 1
Projects left: 1 (cap:1, prof:2), 2 (cap:1, prof:3)
Available Projects (capital <= 1): Project 1, Project 2
Pick max profit: Project 2 (profit 3)
Do Project 2 -> w = 1 + 3 = 4
Max Capital = 4Examples
Level I: Brute Force Greedy Selection
Intuition
w) and that yields the maximum profit. Once we finish it, our w increases, potentially unlocking new jobs. We can simply scan the list of projects up to k times, picking the best affordable project each time.Detailed Dry Run
- k=1: Scan all. P0(0<=0, prof 1), P1(1>0), P2(1>0). Best is P0. w=0+1=1. Mark P0 used.
- k=2: Scan all. P0(used), P1(1<=1, prof 2), P2(1<=1, prof 3). Best is P2. w=1+3=4. Mark P2 used. Return w=4.
Level II: Sort Projects by Profit and Scan
Intuition
Detailed Dry Run
- k=1: Scan. (3, cap:1 > 0) skip. (2, cap:1 > 0) skip. (1, cap:0 <= 0) PICK. w = 0 + 1 = 1.
- k=2: Scan. (3, cap:1 <= 1) PICK. w = 1 + 3 = 4. Return w = 4.
Level III: Two Heaps (Optimal)
Intuition
w grows, we transfer projects from the "can't afford" group to the "can afford" group. This perfectly maps to using a Min-Heap for capital and a Max-Heap for profits.Detailed Dry Run
- Pair & Sort by Capital: [(0,1), (1,2), (1,3)] -> Min-Heap equivalent.
- w=0. Move affordable to Max-Heap (profits). Max-Heap gets (profit=1) from (0,1). Max-Heap = [1].
- Can't move (1,2) or (1,3) since 1 > 0.
- Do job 1 (k=1): pop Max-Heap (1). w = 0 + 1 = 1.
- New w=1. Check Min-Heap. Both (1,2) and (1,3) are now affordable. Push their profits (2, 3) to Max-Heap. Max-Heap = [3, 2].
- Do job 2 (k=2): pop Max-Heap (3). w = 1 + 3 = 4.
- k=2 reached. Return w=4.
Kth Smallest Element in Sorted Matrix
n x n matrix where each of the rows and columns is sorted in ascending order, return the kth smallest element in the matrix.kth smallest element in the sorted order, not the kth distinct element.Visual Representation
matrix =
[ 1, 5, 9 ]
[ 10, 11, 13 ]
[ 12, 13, 15 ]
k = 8
All elements sorted: [1, 5, 9, 10, 11, 12, 13, 13, 15]
The 8th smallest is 13.
Min-Heap approach (similar to Merge K sorted lists):
Initial heap: [(1,0,0)] <- (val, row, col)
Expand smallest, add right neighbor and maybe downExamples
Level I: Flatten and Sort
Intuition
k - 1. While not leveraging the sorted property of the matrix, this is intuitive and correct.Detailed Dry Run
- Flatten: [1, 5, 9, 10, 11, 13, 12, 13, 15]
- Sort: [1, 5, 9, 10, 11, 12, 13, 13, 15]
- Return sorted[k-1] = sorted[7] = 13
Level II: Binary Search on Value Range
Intuition
X has a predictable number of elements smaller than or equal to it. We can binary search for the value X in the range [matrix[0][0], matrix[n-1][n-1]]. For each middle value, we count how many elements are <= mid in time using the sorted property.Detailed Dry Run
Level III: Min-Heap (K Merged Sorted Lists)
Intuition
k pops, the last popped element is the answer. Optimized: we only need to start with the first column (N elements) and expand row by row.Detailed Dry Run
- Pop (1). Push right (5,0,1). Heap=[(5,0,1),(10,1,0),(12,2,0)]. Count=1.
- Pop (5). Push (9,0,2). Count=2.
- Pop (9). No right (col 3 out of range). Count=3.
- Pop (10). Push (11,1,1). Count=4.
- Pop (11). Push (13,1,2). Count=5.
- Pop (12). Push (13,2,1). Count=6.
- Pop (13). Push (13,1,3) - out of range. Count=7.
- Pop (13). Count=8. Return 13.
Maximum Performance of a Team
n and k and two integer arrays speed and efficiency both of length n. There are n engineers numbered from 1 to n. speed[i] and efficiency[i] represent the speed and efficiency of the ith engineer respectively.k engineers out of the n engineers to form a team with the maximum performance.10^9 + 7.Visual Representation
n=6, k=2, speed=[2,10,3,1,5,8], efficiency=[5,4,3,9,7,2]
Key Insight: Sort by efficiency descending.
For each engineer i as the "min efficiency" of the group,
pick the k fastest engineers from 0..i (including i).
Sorted by eff desc: (9,1),(7,5),(5,2),(4,10),(3,3),(2,8)
- Min eff = 9: Team = [(1,9)]. Perf = 1*9 = 9
- Min eff = 7: Team = [(1,9),(5,7)]. Sum speeds=6. Perf=6*7=42
- Min eff = 5: Team = [(2,5),(5,7),(1,9)]. Speeds=[1,5,2]. Sum k=2 fastest=5+2=7. Perf=7*5=35
- Min eff = 4: Team picks (10,4) as one, need 2 fastest. Max perf = (10+5)*4 = 60Examples
Level I: Brute Force - Check All Subsets
Intuition
k engineers from the n engineers. For each subset, compute performance = (sum of speeds) * (minimum efficiency). Return the maximum. This is correct but exponential in complexity.Detailed Dry Run
Level II: Sort by Efficiency and Search K-Fastest
Intuition
i, if we consider them as the minimum efficiency in the team, we only need to look at engineers from 0 to i (who all have efficiency >= eff[i]) and pick the k fastest ones.Detailed Dry Run
- i=0, Eff=9: prefix=[1]. Sum k=2 fastest = 1. Perf = 1*9=9.
- i=1, Eff=5: prefix=[1,2]. Sum k=2 fastest = 3. Perf = 3*5=15.
- i=2, Eff=4: prefix=[1,2,10]. Sum k=2 fastest = 12. Perf = 12*4=48.
- i=3, Eff=3: prefix=[1,2,10,3]. Sum k=2 fastest = 13. Perf = 13*3=39. Max = 48.
Level III: Sort by Efficiency + Min-Heap (Optimal)
Intuition
efficiency[i], then we should include engineer i in the team AND pick the k-1 fastest engineers from all engineers who have efficiency >= efficiency[i].i has the minimum efficiency seen so far. We need the maximum sum of speeds from engineer 0 to i. We maintain a Min-Heap of size k storing speeds — when the heap exceeds k, we pop the smallest speed. This ensures our heap always holds the k largest speeds.Detailed Dry Run
- (9,sp=1): push 1. sum=1. size=1<=2. perf=1*9=9. best=9.
- (7,sp=5): push 5. sum=6. size=2<=2. perf=6*7=42. best=42.
- (5,sp=2): push 2. sum=8. size=3>2. pop min(1). sum=7. perf=7*5=35. best=42.
- (4,sp=10): push 10. sum=17. size=3>2. pop min(2). sum=15. perf=15*4=60. best=60.
- (3,sp=3): push 3. sum=18. size=3>2. pop min(3). sum=15. perf=15*3=45. best=60. Return 60 % MOD = 60
Minimum Interval to Include Each Query
intervals, where intervals[i] = [left_i, right_i] represents an inclusive interval [left_i, right_i]. You are also given an integer array queries.jth query is the size of the smallest interval i such that left_i <= queries[j] <= right_i. The size of an interval is equal to right_i - left_i + 1.Visual Representation
intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5]
Query 2: Intervals covering 2 -> [1,4](size 4), [2,4](size 3). Min = 3
Query 3: Intervals covering 3 -> [1,4](size 4), [2,4](size 3), [3,6](size 4). Min = 3
Query 4: Intervals covering 4 -> [1,4](size 4), [2,4](size 3), [3,6](size 4), [4,4](size 1). Min = 1
Query 5: Intervals covering 5 -> [3,6](size 4). Min = 4Examples
Level I: Brute Force - Check Every Interval Per Query
Intuition
Detailed Dry Run
Level II: Sort Intervals by Size and Scan
Intuition
Detailed Dry Run
Level III: Sort + Min-Heap (Sweep Line Approach)
Intuition
- Add all intervals whose start
<= current queryto the Min-Heap (they might cover this query). - Remove all intervals from the top of the heap whose end
< current query(they expired). - The top of the heap (if any) is the smallest valid interval covering the query.
Detailed Dry Run
Maximum Number of Events
events where events[i] = [startDay_i, endDay_i]. Every event i starts at startDay_i and ends at endDay_i.i at any day d where startDay_i <= d <= endDay_i. You can only attend one event per day.Visual Representation
events = [[1,2],[2,3],[3,4]]
Day 1: [1,2] available. Attend it.
Day 2: [2,3] available. Attend it.
Day 3: [3,4] available. Attend it.
Total = 3
Key insight: Each day, attend the event that ends SOONEST (greedy).
This leaves later-ending events available for future days.Examples
Level I: Greedy - Sort by Start, Attend First Available
Intuition
Detailed Dry Run
Level II: Sort by Start + Daily Min-End Search
Intuition
Detailed Dry Run
Level III: Sort by Start + Min-Heap of End Days (Optimal)
Intuition
- Iterate over each day from 1 to maxDay.
- Add all events that start on this day to the Min-Heap.
- Remove all expired events (heap top end < today).
- If the heap isn't empty, attend the event ending soonest (pop from heap), increment count.
Detailed Dry Run
Data Stream as Disjoint Intervals
a1, a2, ..., an, summarize the numbers seen so far as a list of disjoint intervals.SummaryRanges class:SummaryRanges()Initializes the object with an empty stream.void addNum(int value)Adds the integervalueto the stream.int[][] getIntervals()Returns a summary of the integers in the stream currently as a list of disjoint intervals[start_i, end_i]. The answer should be sorted bystart_i.
Visual Representation
addNum(1): [1,1]
addNum(3): [1,1], [3,3]
addNum(7): [1,1], [3,3], [7,7]
addNum(2): [1,3], [7,7] <-- 2 merges [1,1] and [3,3]
addNum(6): [1,3], [6,7] <-- 6 merges with [7,7]
Key: When adding N, find and merge with adjacent intervals.
[L, N-1] + N + [N+1, R] => [L, R]Examples
Level I: Brute Force - Rebuild on Every getIntervals
Intuition
getIntervals() call, rebuild the disjoint intervals from scratch by scanning through the sorted list and merging consecutive numbers.Detailed Dry Run
Level II: Maintenance of Sorted Intervals
Intuition
getIntervals at the cost of for addNum due to array shifts.Detailed Dry Run
Level III: TreeMap / Sorted Map for O(log N) addNum
Intuition
start. When adding a new number val:- Find the interval that might start right after
val+1(right neighbor). - Find the interval whose start <=
val(left neighbor), and check if it ends atval-1. - Based on overlapping/adjacency with left and right neighbors, merge intervals accordingly.
O(log N) per addNum and O(N) per getIntervals.Detailed Dry Run
Smallest Range Covering Elements from K Lists
k lists of sorted integers in non-decreasing order. Find the smallest range that includes at least one number from each of the k lists.[a, b] is smaller than range [c, d] if b - a < d - c, or a < c if b - a == d - c.Visual Representation
nums = [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
Initial elements from each list: {4, 0, 5}
Range: [0, 5], Size: 5
To find a smaller range, we must increase the minimum (0).
Next element from List 1 (was 0): 9
Set: {4, 9, 5}
Range: [4, 9], Size: 5 (same size, but 4 > 0, so not 'smaller' by definition)
Next element from List 0 (was 4): 10
Set: {10, 9, 5}
Range: [5, 10], Size: 5
...
Eventually we find [20, 24], Size: 4.Examples
Level I: Brute Force - Check All Pairs
Intuition
[start, end], check if it contains at least one number from each of the k lists. Keep track of the smallest such range.Detailed Dry Run
Level II: Sliding Window on All Elements
Intuition
Detailed Dry Run
Level III: K-Way Min-Heap Search (Optimal)
Intuition
k elements in a Min-Heap. The current range is defined by [min_in_heap, max_in_heap]. To try and find a smaller range, we must increase the minimum element by popping it and replacing it with the next element from that same list. As we go, we keep track of the maximum value currently in our set to update the range.Detailed Dry Run
- Pop 0. Next L1 is 9. Heap=[(4,0,0), (5,2,0), (9,1,1)]. MaxVal = 9. Range=[4,9], Size 5.
- Pop 4. Next L0 is 10. Heap=[(5,2,0), (9,1,1), (10,0,1)]. MaxVal = 10. Range=[5,10], Size 5.
- Pop 5. Next L2 is 18. Heap=[(9,1,1), (10,0,1), (18,2,1)]. MaxVal = 18. Range=[9,18], Size 9. ... Eventually we hit [20, 24].
Kth Smallest Prime Fraction
arr containing 1 and prime numbers, where all the integers of arr are unique. You are also given an integer k.i and j where 0 <= i < j < arr.length, we consider the fraction arr[i] / arr[j].kth smallest fraction considered. Return your answer as an array of integers of size 2, where answer[0] = arr[i] and answer[1] = arr[j].Visual Representation
arr = [1, 2, 3, 5], k = 3
All fractions:
1/5, 1/3, 2/5, 1/2, 3/5, 2/3
Sorted: 1/5, 1/3, 2/5, 1/2, 3/5, 2/3
3rd smallest: 2/5
Heap strategy: Start with 1/5, 1/3, 1/2.
Pop smallest (1/5), push next numerator: 2/5.
Pop smallest (1/3), push next: 2/3.
Pop smallest (2/5). This is the 3rd pop -> Result [2, 5].Examples
Level I: Brute Force - Generate and Sort
Intuition
arr[i] / arr[j] where i < j. Store them in a list, sort the list by fraction value, and return the kth element. Simple but slow for large arrays.Detailed Dry Run
Level II: Binary Search on Value Range
Intuition
X such that there are exactly k fractions smaller than or equal to X. For a given X, we can count how many fractions satisfy arr[i] / arr[j] <= X (or arr[i] <= X * arr[j]) in time using two pointers.Detailed Dry Run
Level III: Min-Heap (Sorted Pointers)
Intuition
arr[j], the possible numerators arr[0], arr[1], ..., arr[j-1] create a sorted sequence of fractions. We can use a Min-Heap to store the smallest fraction for each possible denominator arr[j]. We pop the overall smallest and replace it with the next numerator from that same denominator's list.Detailed Dry Run
- Pop 1/5. Next num for denom 5 is 2. Heap: {1/3, 1/2, 2/5}. Pop count = 1.
- Pop 1/3. Next num for denom 3 is 2. Heap: {1/2, 2/5, 2/3}. Pop count = 2.
- Pop 2/5. Pop count = 3. Done. Result [2, 5].
Course4All Technical Board
Verified ExpertSenior Software Engineers & Algorithmic Experts
Our DSA content is authored and reviewed by engineers from top tech firms to ensure optimal time and space complexity analysis.
Found an issue or have a suggestion?
Help us improve! Report bugs or suggest new features on our Telegram group.