Skip to content

Added C# solutions for Chapter 8: Heaps #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 15, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions csharp/Heaps/CombineSortedLinkedLists.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using ds.ListNode;

/*
Definition of ListNode:
class ListNode
{
public ListNode(int val, ListNode next = null)
{
Val = val;
Next = next;
}

public int Val { get; set; }

public ListNode Next { get; set; }
}
*/

class ListNodeComparer : IComparer<ListNode>
{
public int Compare(ListNode a, ListNode b)
{
return a.Val - b.Val;
}
}

public class Solution
{
public ListNode CombineSortedLinkedLists(ListNode[] lists)
{
PriorityQueue<ListNode, ListNode> heap = new(new ListNodeComparer());

// Push the head of each linked list into the heap.
foreach (ListNode head in lists)
if (head != null)
heap.Enqueue(head, head);

// Set a dummy node to point to the head of the output linked list.
ListNode dummy = new ListNode(-1);

// Create a pointer to iterate through the combined linked list as
// we add nodes to it.
ListNode curr = dummy;

while (heap.Count > 0)
{
// Pop the node with the smallest value from the heap and add it
// to the output linked list
ListNode smallestNode = heap.Dequeue();
curr.Next = smallestNode;
curr = curr.Next;

// Push the popped node's subsequent node to the heap.
if (smallestNode.Next != null)
heap.Enqueue(smallestNode.Next, smallestNode.Next);
}

return dummy.Next;
}
}
52 changes: 52 additions & 0 deletions csharp/Heaps/KMostFrequentStringsMaxHeap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using ds.Pair;

/*
Definition of Pair:
class Pair
{
public string Str { get; }
public int Freq { get; }

public Pair(string str, int freq)
{
Str = str;
Freq = freq;
}
}
*/

class MaxHeapPairComparer : IComparer<Pair>
{
public int Compare(Pair a, Pair b)
{
// Prioritize lexicographical order for strings with equal frequencies.
if (a.Freq == b.Freq)
return string.Compare(a.Str, b.Str, StringComparison.Ordinal);

// Otherwise, prioritize strings with higher frequencies.
return b.Freq - a.Freq;
}
}

public class Solution
{
public string[] KMostFrequentStringsMaxHeap(string[] strs, int k)
{
// We use a Dictionary to count the frequency of each string.
Dictionary<string, int> freqs = new Dictionary<string, int>();
foreach (string str in strs)
freqs[str] = freqs.GetValueOrDefault(str) + 1;

// Create the max heap by adding all Pair objects.
PriorityQueue<Pair, Pair> maxHeap = new(new MaxHeapPairComparer());
foreach ((string str, int freq) in freqs)
maxHeap.Enqueue(new Pair(str, freq), new Pair(str, freq));

// Pop the most frequent strings off the heap 'k' times.
List<string> result = new();
for (int i = 0; i < k && maxHeap.Count > 0; i++)
result.Add(maxHeap.Dequeue().Str);

return result.ToArray();
}
}
63 changes: 63 additions & 0 deletions csharp/Heaps/KMostFrequentStringsMinHeap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using ds.Pair;

/*
Definition of Pair:
class Pair
{
public string Str { get; }
public int Freq { get; }

public Pair(string str, int freq)
{
Str = str;
Freq = freq;
}
}
*/

// Since this is a min-heap comparator, we define it to prioritize
// lower frequency, and in case of tie, lexicographically larger string.
class MinHeapPairComparer : IComparer<Pair>
{
public int Compare(Pair a, Pair b)
{
if (a.Freq == b.Freq)
return string.Compare(b.Str, a.Str, StringComparison.Ordinal); // Reverse order for tie

return a.Freq - b.Freq; // Lower frequency has higher priority
}
}

public class Solution
{
public string[] KMostFrequentStringsMinHeap(string[] strs, int k)
{
// Count the frequency of each string using a dictionary.
Dictionary<string, int> freqs = new Dictionary<string, int>();
foreach (string str in strs)
freqs[str] = freqs.GetValueOrDefault(str) + 1;

// Initialize the min-heap with custom Pair comparator.
PriorityQueue<Pair, Pair> minHeap = new(new MinHeapPairComparer());

// Add all (string, frequency) pairs to the heap.
foreach ((string str, int freq) in freqs)
{
minHeap.Enqueue(new Pair(str, freq), new Pair(str, freq));

// If heap size exceeds 'k', pop the lowest frequency string to
// ensure the heap only contains the 'k' most frequent words so far.
if (minHeap.Count > k)
minHeap.Dequeue();
}

// Pop the remaining 'k' strings and reverse the result so that
// most frequent strings are listed first.
List<string> result = [];
while (minHeap.Count > 0)
result.Add(minHeap.Dequeue().Str);

result.Reverse();
return result.ToArray();
}
}
49 changes: 49 additions & 0 deletions csharp/Heaps/MedianOfAnIntegerStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
public class MedianOfAnIntegerStream
{
PriorityQueue<int, int> leftHalf; // max-heap
PriorityQueue<int, int> rightHalf; // min-heap

public MedianOfAnIntegerStream()
{
leftHalf = new(Comparer<int>.Create((x, y) => y - x));
rightHalf = new(Comparer<int>.Create((x, y) => x - y));
}

public void Add(int num)
{
// If 'num' is less than or equal to the max of 'leftHalf', it
// belongs to the left half.
if (leftHalf.Count == 0 || num <= leftHalf.Peek())
{
leftHalf.Enqueue(num, num);

// Rebalance the heaps if the size of the 'leftHalf'
// exceeds the size of the 'rightHalf' by more than one.
if (leftHalf.Count > rightHalf.Count + 1)
{
int leftTop = leftHalf.Dequeue();
rightHalf.Enqueue(leftTop, leftTop);
}
}
// Otherwise, it belongs to the right half.
else
{
rightHalf.Enqueue(num, num);

// Rebalance the heaps if 'rightHalf' is larger than 'leftHalf'.
if (leftHalf.Count < rightHalf.Count)
{
int rightTop = rightHalf.Dequeue();
leftHalf.Enqueue(rightTop, rightTop);
}
}
}

public double GetMedian()
{
if (leftHalf.Count == rightHalf.Count)
return (leftHalf.Peek() + rightHalf.Peek()) / 2.0;

return leftHalf.Peek();
}
}
29 changes: 29 additions & 0 deletions csharp/Heaps/SortAKSortedArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
public class Solution
{
public int[] SortAKSortedArray(int[] nums, int k)
{
PriorityQueue<int, int> minHeap = new(Comparer<int>.Create((x, y) => x - y));

// Populate a min-heap with the first k + 1 values in 'nums'.
for (int i = 0; i < k + 1; i++)
minHeap.Enqueue(nums[i], nums[i]);

// Replace elements in the array with the minimum from the heap at each iteration.
int insertIndx = 0;
for (int i = k + 1; i < nums.Length; i++)
{
nums[insertIndx] = minHeap.Dequeue();
insertIndx++;
minHeap.Enqueue(nums[i], nums[i]);
}

// Pop the remaining elements from the heap to finish sorting the array.
while (minHeap.Count > 0)
{
nums[insertIndx] = minHeap.Dequeue();
insertIndx++;
}

return nums;
}
}