Sliding Window Median with .NET 9

.NET 9 introduced support for the Remove method in PriorityQueue: boolean removed = priorityQueue.Remove(element, out var _, out var _); This method is particularly useful for solving the Sliding Window Median problem on LeetCode. By leveraging two heaps (a max-heap and a min-heap, implemented with PriorityQueue), it allows for the immediate removal of elements that fall out of the sliding window. However, the time complexity of the Remove operation is linear, O(n)O(n) O(n) . public class Solution { // For a max-heap with negative values, define a custom comparer instead of using the negative priority trick private PriorityQueue maxHeap = new(Comparer.Create((a, b) => b.CompareTo(a))); private PriorityQueue minHeap = new(); public double[] MedianSlidingWindow(int[] nums, int k) { var res = new List(); for(var i = 0; i = k) { Remove(nums[i-k]); } Add(nums[i]); if (i >= k - 1) { res.Add(GetMedian()); } } return res.ToArray(); } private void Add(int n) { // Another feature in PriorityQueue: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.priorityqueue-2.enqueuedequeue?view=net-9.0 var m = maxHeap.EnqueueDequeue(n, n); minHeap.Enqueue(m, m); if (minHeap.Count - 1 > maxHeap.Count) { m = minHeap.Dequeue(); maxHeap.Enqueue(m, m); } } private void Remove(int n) { // Support for the Remove method, introduced in .NET 9 if (!minHeap.Remove(n, out var _, out var _)) { maxHeap.Remove(n, out var _, out var _); } } private double GetMedian() { if (minHeap.Count != maxHeap.Count) { return minHeap.Peek(); } // Cast to long to prevent overflow when adding values (e.g., int.MaxValue + int.MaxValue) return ((long)minHeap.Peek() + maxHeap.Peek()) / 2.0; } } Learn more about PriorityQueue in .NET: https://andrewlock.net/behind-the-implementation-of-dotnets-priorityqueue/ https://blog.xeynergy.com/whats-new-in-net-9-updated-priority-queues-in-collections-13b067d34c42

Jan 18, 2025 - 16:27
Sliding Window Median with .NET 9

.NET 9 introduced support for the Remove method in PriorityQueue:

boolean removed = priorityQueue.Remove(element, out var _, out var _);

This method is particularly useful for solving the Sliding Window Median problem on LeetCode. By leveraging two heaps (a max-heap and a min-heap, implemented with PriorityQueue), it allows for the immediate removal of elements that fall out of the sliding window. However, the time complexity of the Remove operation is linear, O(n)O(n) O(n) .

public class Solution {
    // For a max-heap with negative values, define a custom comparer instead of using the negative priority trick
    private PriorityQueue<int, int> maxHeap = new(Comparer<int>.Create((a, b) => b.CompareTo(a)));
    private PriorityQueue<int, int> minHeap = new();

    public double[] MedianSlidingWindow(int[] nums, int k) {
        var res = new List<double>();

        for(var i = 0; i < nums.Length; i++) {
            if (i >= k) {
                Remove(nums[i-k]);
            }

            Add(nums[i]);

            if (i >= k - 1) {
                res.Add(GetMedian());
            }
        }

        return res.ToArray();
    }

    private void Add(int n) {
        // Another feature in PriorityQueue: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.priorityqueue-2.enqueuedequeue?view=net-9.0
        var m = maxHeap.EnqueueDequeue(n, n);
        minHeap.Enqueue(m, m);

        if (minHeap.Count - 1 > maxHeap.Count)
        {
            m = minHeap.Dequeue();
            maxHeap.Enqueue(m, m);
        }
    }

    private void Remove(int n) {
        // Support for the Remove method, introduced in .NET 9
        if (!minHeap.Remove(n, out var _, out var _)) {
            maxHeap.Remove(n, out var _, out var _);
        }
    }

    private double GetMedian() {
        if (minHeap.Count != maxHeap.Count) {
            return minHeap.Peek();
        }

        // Cast to long to prevent overflow when adding values (e.g., int.MaxValue + int.MaxValue)
        return ((long)minHeap.Peek() + maxHeap.Peek()) / 2.0;
    }
}

Learn more about PriorityQueue in .NET: