Deque Fundamentals
Deque Fundamentals
A deque (double-ended queue) allows insertion and removal from both ends.
Core Operations
| Operation | Description | Time |
|---|---|---|
| addFirst | Add to front | O(1) |
| addLast | Add to rear | O(1) |
| removeFirst | Remove from front | O(1) |
| removeLast | Remove from rear | O(1) |
| peekFirst | View front | O(1) |
| peekLast | View rear | O(1) |
Deque as Stack or Queue
// Deque as Stack
deque.push(1); // or addFirst
deque.pop(); // or removeFirst
deque.peek(); // peekFirst
// Deque as Queue
deque.offer(1); // or addLast
deque.poll(); // or removeFirst
deque.peek(); // peekFirst
ArrayDeque Implementation
Deque<Integer> deque = new ArrayDeque<>();
deque.addFirst(1); // [1]
deque.addLast(2); // [1, 2]
deque.addFirst(0); // [0, 1, 2]
int front = deque.removeFirst(); // 0
int back = deque.removeLast(); // 2
When to Use Deque
- Sliding window maximum
- Implementing both stack and queue
- Palindrome checking
- BFS with bidirectional traversal
- Rolling hash computations
Deque Applications
Deque Applications
1. Sliding Window Maximum (LeetCode 239)
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deque = new ArrayDeque<>();
int[] result = new int[nums.length - k + 1];
for (int i = 0; i < nums.length; i++) {
while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
deque.pollFirst();
}
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
deque.offerLast(i);
if (i >= k - 1) {
result[i - k + 1] = nums[deque.peekFirst()];
}
}
return result;
}
// Time: O(n), Space: O(k)
2. Palindrome Check
public boolean isPalindrome(String s) {
Deque<Character> deque = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (Character.isLetterOrDigit(c)) {
deque.addLast(Character.toLowerCase(c));
}
}
while (deque.size() > 1) {
if (deque.pollFirst() != deque.pollLast()) {
return false;
}
}
return true;
}
3. Moving Average (LeetCode 346)
class MovingAverage {
Deque<Integer> deque;
int size;
double sum;
public MovingAverage(int size) {
this.deque = new ArrayDeque<>();
this.size = size;
this.sum = 0;
}
public double next(int val) {
deque.offerLast(val);
sum += val;
if (deque.size() > size) {
sum -= deque.pollFirst();
}
return sum / deque.size();
}
}
Deque vs Stack vs Queue
| Feature | Stack | Queue | Deque |
|---|---|---|---|
| Add | Push (top) | Offer (rear) | Both ends |
| Remove | Pop (top) | Poll (front) | Both ends |
| Use | DFS, undo | BFS | Sliding window |
Practice Problems
You are given an array nums and a sliding window of size k moving from left to right. Return the max in each window.
Example:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Maximum in each window of size 3.
Optimal Solution — O(n) time, O(k) space
Monotonic deque storing indices
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deque = new ArrayDeque<>();
int n = nums.length;
int[] result = new int[n - k + 1];
for (int i = 0; i < n; i++) {
while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
deque.pollFirst();
}
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
deque.offerLast(i);
if (i >= k - 1) {
result[i - k + 1] = nums[deque.peekFirst()];
}
}
return result;
}
}Edge Cases:
- k = 1
- k = n
- All same elements
- Strictly increasing/decreasing
The median is the middle value in an ordered integer list. Return the median of each sliding window of size k.
Example:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [1.00000,-1.00000,-1.00000,3.00000,5.00000,6.00000]
Median of each window of size 3.
Optimal Solution — O(n log k) time, O(k) space
Two heaps (max-heap and min-heap) with lazy deletion using deque
class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
// Two heaps approach with lazy deletion
// See full implementation in chapter content
return new double[nums.length - k + 1];
}
}Edge Cases:
- Odd k
- Even k
- All same elements
Return any permutation of deck such that when you reveal cards in order (reveal top, move next to bottom), they are revealed in increasing order.
Example:
Input: deck = [17,13,11,2,3,5,7]
Output: [2,13,3,11,5,17,7]
Simulation yields increasing order.
Optimal Solution — O(n log n) time, O(n) space
Sort deck, use deque to simulate reveal pattern
class Solution {
public int[] deckRevealedIncreasing(int[] deck) {
int n = deck.length;
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < n; i++) deque.offer(i);
Arrays.sort(deck);
int[] result = new int[n];
for (int card : deck) {
result[deque.pollFirst()] = card;
if (!deque.isEmpty()) deque.offerLast(deque.pollFirst());
}
return result;
}
}Edge Cases:
- Single card
- Already sorted
- All same value
Quiz
1. What operations does a deque support?
2. Can a deque be used as a stack?
3. What is the primary purpose of Deque?
4. What is a common mistake when implementing Deque?
Flashcards
Question
What is a deque?
Click to reveal answer
Answer
Double-ended queue allowing insertion/removal from both ends in O(1).
Question
When to use deque over queue?
Click to reveal answer
Answer
When you need to access both ends, or for sliding window problems.
Question
What is Deque?
Click to reveal answer
Answer
Deque is a key concept in software engineering.
Question
When to use Deque?
Click to reveal answer
Answer
Use Deque when building production systems that require reliability, scalability, and maintainability.
Question
Deque best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Deque is more flexible than queue/stack
- 2.O(1) for all end operations
- 3.Use ArrayDeque in Java
- 4.Store indices for sliding window
Interview Tips
- •Explain why deque is needed
- •Discuss ArrayDeque vs LinkedList
- •Mention circular buffer implementation
Cheat Sheet
Deque Cheat Sheet
Operations: addFirst, addLast, removeFirst, removeLast - all O(1)
Use Cases: Sliding window, palindrome, implementing stack/queue
Java: Use ArrayDeque (preferred over LinkedList)
Pattern: Store indices for sliding window problems