Recommended resources
The freely available resources this lesson will direct you to.
Hello! Welcome to our third lesson.
In our last session, we differentiated between Python's various dictionary types: dict, OrderedDict, and defaultdict. You learned to select the right tool for tasks ranging from general storage to implementing complex logic like an LRU cache.
Today, we'll continue our deep dive into the collections module by focusing on another high-performance data structure. This lesson will address the learning outcome: Implement efficient queue-based and sliding-window algorithms using collections.deque.
The deque (pronounced "deck") is a fundamental tool for any engineer building systems that process data sequentially. Given your experience with scheduling and queuing in Rust with your work on Rudi, you'll find the performance characteristics and use cases of deque especially relevant. Understanding when and why to use it over a standard list is a key indicator of a seasoned Python developer.
1. The Performance Pitfall of Using Lists as Queues
In many languages, an array or list is a common choice for simple queue-like behavior. However, in Python, using a list for this purpose can introduce significant performance bottlenecks. A list is implemented as a dynamic array, which means adding or removing elements from the end is fast (O(1) amortized time), but doing so from the beginning is slow (O(n)).
This is because removing the first element requires shifting all subsequent elements one position to the left. For a large list inside a loop, this cost adds up dramatically.
Idiomatic Python: Deques vs Lists
To see a practical demonstration of this inefficiency, let's watch the first part of the video 'Idiomatic Python: Deques vs Lists' from MathByte Academy.
Watch from the beginning until 04:47. The video will time the performance of inserting and deleting elements at both the beginning and the end of a Python list. Pay close attention to the dramatic time difference between front-end and back-end operations.
This performance gap is precisely the problem collections.deque was designed to solve.

2. Introducing collections.deque: The Right Tool for the Job
A deque is a double-ended queue. It's implemented as a doubly linked list under the hood, not a dynamic array. This structure means that the time complexity for adding or removing an element from either end is O(1).
This makes deque the ideal data structure for implementing queues and other patterns that require efficient access to both ends of a sequence.
Let's continue with the same video to see how to use the deque API and how its performance compares.
Idiomatic Python: Deques vs Lists
The next part of the video introduces the deque object, its core methods, and a direct performance comparison against the list timings we just saw.
Please watch from 04:47 to 11:49, and then from 13:36 to 16:45. Focus on: The core concept: How deque provides O(1) complexity for operations on both ends (04:47 - 06:56). The API: The usage of append, appendleft, pop, and popleft (06:56 - 11:49). The performance proof: The timing comparisons that directly show deque's speed advantage for front-end operations (13:36 - 16:45).
The trade-off for this efficiency is that accessing elements in the middle of a deque by index (my_deque[i]) is an O(n) operation, whereas it's O(1) for a list. Therefore, you should choose deque when your primary use case involves adding and removing from the ends, and list when you need fast random access.
3. Implementing Efficient Queues
With its O(1) append and pop operations on both ends, deque is perfectly suited for building queues.
- FIFO (First-In, First-Out) Queue: This is the most common queue type. You add items to one end (enqueue) and remove them from the other (dequeue).
- Enqueue:
my_deque.append(item) - Dequeue:
my_deque.popleft()
- Enqueue:
The Real Python article "Python's deque" provides an excellent guide on this. It not only shows the basic usage but also demonstrates how you might build a more formal Queue class, which is a great exercise in creating clean, production-ready abstractions.
Python's deque: Implement Efficient Queues and Stacks
Let's read a section from 'Python's deque: Implement Efficient Queues and Stacks' on Real Python. It covers implementing a FIFO queue and introduces a key feature for sliding windows: maxlen.
Please read the following two sections (about 8 minutes): "Build Efficient Queues With deque": This section shows how to use append() and popleft() to create a FIFO queue and wraps it in a custom class for a cleaner API. "Limiting the Number of Items: maxlen": Read this subsection to understand how to create a bounded deque. This feature is the foundation for many sliding-window use cases.
The maxlen argument is particularly powerful. When a bounded deque is full, adding a new item to one end automatically discards an item from the opposite end. This "sliding" behavior is exactly what we need for sliding window algorithms.
4. Advanced Application: Sliding Window Maximum
Sliding window problems are a common category of algorithm questions in interviews. They involve processing a fixed-size "window" that moves across a larger sequence of data. A classic example is the Sliding Window Maximum problem.
Problem: Given an array of numbers and a window size k, find the maximum value within the window as it slides from left to right.

A brute-force solution would be to recalculate the maximum of the k elements for each of the n-k+1 windows, leading to an O(n*k) time complexity. This is too slow for large inputs.
We can achieve a much more efficient O(n) solution by using a deque to maintain a monotonic queue. This queue will store indices of elements from the input array, and we will enforce a special rule: the values at these indices in the queue will always be in decreasing order.
This ensures two things:
- The leftmost element in the
dequeis always the index of the largest number in the current window. - We can efficiently add new elements and remove old ones while maintaining this property.
This concept can be tricky, so a visual explanation is best.
Sliding Window Maximum - Monotonic Queue - Leetcode 239
The video 'Sliding Window Maximum' by NeetCode provides one of the clearest explanations of the monotonic queue algorithm.
Watch from 02:19 to 15:36. The video is broken down into a few key parts: Core Idea (02:19 - 05:06): Understand the intuition behind discarding smaller elements that are no longer relevant. Algorithm Walkthrough (05:06 - 11:53): Follow the step-by-step example of how the deque is managed—adding elements to the right, removing outdated elements from the left, and keeping it monotonically decreasing. Python Implementation (11:53 - 15:36): See how this logic translates into Python code using collections.deque.
Let's write down the final algorithm from the video to make sure it's crystal clear.
from collections import deque
def sliding_window_max(nums, k):
output = []
# The deque will store indices from the 'nums' array
q = deque()
l = r = 0
while r < len(nums):
# 1. Pop smaller values from the back of the queue.
# Before adding the new element at index 'r', remove any elements
# from the right of the deque that are smaller than it. They can
# no longer be the maximum.
while q and nums[q[-1]] < nums[r]:
q.pop()
# 2. Add the new element's index to the back.
q.append(r)
# 3. Remove the leftmost element if it's out of the window.
# The left boundary of the window is `r - k + 1`.
if q[0] < r - k + 1:
q.popleft()
# 4. If the window is fully formed, record the maximum.
# The maximum is always at the front of the deque.
if (r + 1) >= k:
output.append(nums[q[0]])
r += 1
return output
# Example from the image:
print(sliding_window_max([1, 3, 2, 5, 8, 7], 3)) # Expected: [3, 5, 8, 8]
This pattern is extremely powerful and can be adapted to solve other problems like Sliding Window Minimum. Mastering it is a significant step in your interview preparation.
Conclusion
In this lesson, we explored collections.deque and its role in writing efficient, production-quality Python code.
Key Takeaways:
- Performance: Using a
listas a queue is anO(n)anti-pattern for front-end operations.dequeprovidesO(1)performance for adding and removing elements from both ends. - FIFO Queues:
dequeis the standard tool for implementing FIFO queues usingappend()(enqueue) andpopleft()(dequeue). - Bounded Deques: The
maxlenargument creates a fixed-size deque that automatically discards old elements, making it perfect for tracking recent events or creating a sliding window. - Sliding Window Algorithms: By using a
dequeto maintain a monotonic (decreasing or increasing) queue of indices, you can solve complex problems like Sliding Window Maximum in optimalO(n)time.
Next Lesson
We have now covered several key data structures from the collections module. In our next lesson, we will look at collections.Counter, a specialized dictionary subclass that makes frequency counting and data aggregation tasks incredibly simple and expressive.