Skip to content

Commit 4d3e6d3

Browse files
committed
Kotlin - Chapter 8: Heaps
* Combine Sorted Linked List * K Most Frequent Strings (Min/Max Heap) * Median of an Integer Stream * Sort a K Sorted Array
1 parent 3c4bb50 commit 4d3e6d3

File tree

5 files changed

+142
-0
lines changed

5 files changed

+142
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import java.util.PriorityQueue
2+
import ds.ListNode
3+
4+
/*
5+
Definition of ListNode:
6+
data class ListNode(var value: Int, var next: ListNode? = null)
7+
*/
8+
9+
fun combineSortedLinkedLists(lists: List<ListNode?>): ListNode? {
10+
// Define a custom comparator for 'ListNode', enabling the min-heap
11+
// to prioritize nodes with smaller values.
12+
val heap = PriorityQueue<ListNode> { a, b -> a.value - b.value }
13+
// Push the head of each linked list into the heap.
14+
for (head in lists) {
15+
if (head != null) {
16+
heap.add(head)
17+
}
18+
}
19+
// Set a dummy node to point to the head of the output linked list.
20+
val dummy = ListNode(-1)
21+
// Create a pointer to iterate through the combined linked list as
22+
// we add nodes to it.
23+
var curr = dummy
24+
while (heap.isNotEmpty()) {
25+
// Pop the node with the smallest value from the heap and add it
26+
// to the output linked list.
27+
val smallestNode = heap.poll()
28+
curr.next = smallestNode
29+
curr = curr.next!!
30+
// Push the popped node's subsequent node to the heap.
31+
if (smallestNode.next != null) {
32+
heap.add(smallestNode.next)
33+
}
34+
}
35+
return dummy.next
36+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import java.util.PriorityQueue
2+
3+
data class Pair(val str: String, val freq: Int)
4+
5+
fun kMostFrequentStringsMaxHeap(strs: List<String>, k: Int): List<String> {
6+
// We use 'groupingBy' to create a hash map that counts the frequency
7+
// of each string.
8+
val freqs = strs.groupingBy { it }.eachCount()
9+
// Create the max heap by performing heapify on all string-frequency
10+
val maxHeap =
11+
PriorityQueue<Pair> { a, b -> // Define a custom comparator.
12+
// Prioritize lexicographical order for strings with equal
13+
// frequencies.
14+
if (a.freq == b.freq) b.str.compareTo(a.str)
15+
// Otherwise, prioritize strings with higher frequencies.
16+
else b.freq.compareTo(a.freq)
17+
}
18+
maxHeap.addAll(freqs.map { Pair(it.key, it.value) })
19+
// Pop the most frequent string off the heap 'k' times and return
20+
// these 'k' most frequent strings.
21+
return List(k) { maxHeap.poll().str }
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import java.util.PriorityQueue
2+
3+
data class Pair(val str: String, val freq: Int)
4+
5+
fun kMostFrequentStringsMinHeap(strs: List<String>, k: Int): List<String> {
6+
val freqs = strs.groupingBy { it }.eachCount()
7+
val minHeap =
8+
PriorityQueue<Pair> { a, b ->
9+
// Since this is a min-heap comparator, we can use the same
10+
// comparator as the one used in the max-heap, but reversing the
11+
// inequality signs to invert the priority.
12+
if (a.freq == b.freq) a.str.compareTo(b.str) else a.freq.compareTo(b.freq)
13+
}
14+
for ((str, freq) in freqs) {
15+
minHeap.add(Pair(str, freq))
16+
// If heap size exceeds 'k', pop the lowest frequency string to
17+
// ensure the heap only contains the 'k' most frequent words so
18+
// far.
19+
if (minHeap.size > k) {
20+
minHeap.poll()
21+
}
22+
}
23+
// Return the 'k' most frequent strings by popping the remaining 'k'
24+
// strings from the heap. Since we're using a min-heap, we need to
25+
// reverse the result after popping the elements to ensure the most
26+
// frequent strings are listed first.
27+
return List(k) { minHeap.poll().str }.reversed()
28+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import java.util.PriorityQueue
2+
3+
class MedianOfAnIntegerStream {
4+
private val leftHalf = PriorityQueue<Int>(reverseOrder()) // Max-heap
5+
private val rightHalf = PriorityQueue<Int>() // Min-heap
6+
7+
fun add(num: Int) {
8+
// If 'num' is less than or equal to the max of 'left_half', it
9+
// belongs to the left half.
10+
if (leftHalf.isEmpty() || num <= leftHalf.peek()) {
11+
leftHalf.add(num)
12+
// Rebalance the heaps if the size of the 'left_half'
13+
// exceeds the size of the 'right_half' by more than one.
14+
if (leftHalf.size > rightHalf.size + 1) {
15+
rightHalf.add(leftHalf.poll())
16+
}
17+
// Otherwise, it belongs to the right half.
18+
} else {
19+
rightHalf.add(num)
20+
// Rebalance the heaps if 'right_half' is larger than
21+
// 'left_half'.
22+
if (leftHalf.size < rightHalf.size) {
23+
leftHalf.add(rightHalf.poll())
24+
}
25+
}
26+
}
27+
28+
fun getMedian(): Double {
29+
if (leftHalf.size == rightHalf.size) {
30+
return (leftHalf.peek().toDouble() + rightHalf.peek().toDouble()) / 2.0
31+
}
32+
return leftHalf.peek().toDouble()
33+
}
34+
}

kotlin/Heaps/SortAKSortedArray.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import java.util.PriorityQueue
2+
3+
fun sortAKSortedArray(nums: IntArray, k: Int): IntArray {
4+
val nums = IntArray(nums.size)
5+
// Populate a min-heap with the first k + 1 values in 'nums'.
6+
val minHeap = PriorityQueue<Int>()
7+
for (i in 0 until k + 1) {
8+
minHeap.add(nums[i])
9+
}
10+
// Replace elements in the array with the minimum from the heap at each
11+
// iteration.
12+
var index = 0
13+
for (i in k + 1 until nums.size) {
14+
nums[index++] = minHeap.poll()
15+
minHeap.add(nums[i])
16+
}
17+
// Pop the remaining elements from the heap to finish sorting the array.
18+
while (minHeap.isNotEmpty()) {
19+
nums[index++] = minHeap.poll()
20+
}
21+
return nums
22+
}

0 commit comments

Comments
 (0)