Study notes

STUDY NOTES · DATA STRUCTURES & ALGORITHMS

Binary search, stacks, heaps & intervals
Order is information. Use it.

One binary-search template for everything, monotonic stacks, heaps for top-K and medians, and the sort-then-sweep trick for intervals (P10–P20).

anuragdevon 12th Nov 2026 7 min read Data structures & algorithms · Note 3 of 6

These four patterns all exploit some kind of order. Binary search uses sorted data, or an answer space where “if X works, anything bigger works too”. A monotonic stack keeps just the elements that can still matter. A heap keeps the best K without sorting everything. Interval problems almost always start with a sort by start time.

// THE SHORT VERSION
  • Binary search on the answer is the SDE2 favourite: “minimise the maximum”, “smallest speed that works”.
  • Monotonic stack: next greater or smaller element, histograms. Every element is pushed and popped once.
  • Heap: top K with a min-heap of size K, merge K sorted lists, running median with two heaps.
  • Intervals: sort by start, then sweep.
02

Stack and Monotonic Stack

A monotonic stack keeps elements in increasing or decreasing order. Every element is pushed and popped once, so the whole pass is O(n). It answers “the next or previous greater or smaller element” for every index.

P12. Valid Parentheses

JAVA
boolean isValid(String s) {
    Deque<Character> stack = new ArrayDeque<>();
    for (char c : s.toCharArray()) {
        if (c == '(') stack.push(')');
        else if (c == '[') stack.push(']');
        else if (c == '{') stack.push('}');
        else if (stack.isEmpty() || stack.pop() != c) return false;
    }
    return stack.isEmpty();
}

P13. Daily Temperatures (next greater element)

For each day, how many days until a warmer temperature?

JAVA
int[] dailyTemperatures(int[] t) {
    int[] res = new int[t.length];
    Deque<Integer> stack = new ArrayDeque<>();             // indices, temperatures decreasing
    for (int i = 0; i < t.length; i++) {
        while (!stack.isEmpty() && t[i] > t[stack.peek()]) {
            int j = stack.pop();
            res[j] = i - j;
        }
        stack.push(i);
    }
    return res;
}

Complexity: O(n).

P14. Largest Rectangle in Histogram

Idea: for each bar, find how far it can extend left and right while every bar in between is at least as tall. Keep a stack of indices with increasing heights. When a shorter bar arrives, pop and compute the area for the popped bar.

JAVA
int largestRectangleArea(int[] heights) {
    Deque<Integer> stack = new ArrayDeque<>();
    int best = 0, n = heights.length;
    for (int i = 0; i <= n; i++) {
        int h = (i == n) ? 0 : heights[i];                 // sentinel flushes the stack
        while (!stack.isEmpty() && h < heights[stack.peek()]) {
            int height = heights[stack.pop()];
            int leftBoundary = stack.isEmpty() ? -1 : stack.peek();
            best = Math.max(best, height * (i - leftBoundary - 1));
        }
        stack.push(i);
    }
    return best;
}

Complexity: O(n). Extension: maximal rectangle in a binary matrix (run this on the histogram for each row).

P15. Sliding Window Maximum (monotonic deque)

Idea: the deque holds indices with decreasing values. The front is the maximum of the current window. Drop indices that have left the window from the front.

JAVA
int[] maxSlidingWindow(int[] nums, int k) {
    int[] res = new int[nums.length - k + 1];
    Deque<Integer> dq = new ArrayDeque<>();
    for (int i = 0; i < nums.length; i++) {
        if (!dq.isEmpty() && dq.peekFirst() <= i - k) dq.pollFirst();       // out of window
        while (!dq.isEmpty() && nums[dq.peekLast()] <= nums[i]) dq.pollLast(); // useless smaller ones
        dq.offerLast(i);
        if (i >= k - 1) res[i - k + 1] = nums[dq.peekFirst()];
    }
    return res;
}

Complexity: O(n).

03

Heap / Priority Queue

Use when: you need top K, the K-th element, to merge K sorted streams, or a running median. To find the K largest, keep a min-heap of size K, which gives O(n log k).

P16. Kth Largest Element

JAVA
int findKthLargest(int[] nums, int k) {
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    for (int n : nums) {
        minHeap.offer(n);
        if (minHeap.size() > k) minHeap.poll();
    }
    return minHeap.peek();
}

Complexity: O(n log k). Follow-up: Quickselect gives O(n) on average (O(n²) worst case, which randomisation avoids in practice).

P17. Top K Frequent Elements

JAVA
int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> freq = new HashMap<>();
    for (int n : nums) freq.merge(n, 1, Integer::sum);
    PriorityQueue<Map.Entry<Integer, Integer>> heap =
            new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));
    for (var e : freq.entrySet()) {
        heap.offer(e);
        if (heap.size() > k) heap.poll();
    }
    return heap.stream().mapToInt(Map.Entry::getKey).toArray();
}

Complexity: O(n log k). O(n) alternative: bucket sort by frequency (index = count).

SDE2 follow-up, “top K over a stream across many servers”: each node computes its local top-K and a coordinator merges them. Note that this is only exact if you also bring along the counts for candidates, or use Count-Min Sketch plus a heap for an approximate answer.

P18. Merge K Sorted Lists

JAVA
ListNode mergeKLists(ListNode[] lists) {
    PriorityQueue<ListNode> pq = new PriorityQueue<>(Comparator.comparingInt(n -> n.val));
    for (ListNode l : lists) if (l != null) pq.offer(l);
    ListNode dummy = new ListNode(0), tail = dummy;
    while (!pq.isEmpty()) {
        ListNode node = pq.poll();
        tail.next = node; tail = node;
        if (node.next != null) pq.offer(node.next);
    }
    return dummy.next;
}

Complexity: O(N log k), where N is the total number of nodes. The same idea powers external merge sort, merging sorted log files, and k-way merges in LSM-tree databases.

P19. Find Median from Data Stream (two heaps)

Idea: a max-heap holds the lower half and a min-heap holds the upper half. Keep their sizes balanced (the lower half may have one extra).

JAVA
class MedianFinder {
    private final PriorityQueue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
    private final PriorityQueue<Integer> high = new PriorityQueue<>();

    void addNum(int num) {
        low.offer(num);
        high.offer(low.poll());                            // move the largest of low to high
        if (high.size() > low.size()) low.offer(high.poll());
    }
    double findMedian() {
        return low.size() > high.size() ? low.peek() : (low.peek() + (long) high.peek()) / 2.0;
    }
}

Complexity: O(log n) to add, O(1) for the median.

04

Intervals

Use when: you have ranges such as meetings, bookings or delivery slots. Almost always sort by start, then sweep.

P20. Merge Intervals and Meeting Rooms II

JAVA
// Merge overlapping intervals
int[][] merge(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
    List<int[]> res = new ArrayList<>();
    for (int[] cur : intervals) {
        if (res.isEmpty() || res.get(res.size() - 1)[1] < cur[0]) res.add(cur);
        else res.get(res.size() - 1)[1] = Math.max(res.get(res.size() - 1)[1], cur[1]);
    }
    return res.toArray(new int[0][]);
}

// Minimum meeting rooms (= max number of overlapping intervals at any time)
int minMeetingRooms(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
    PriorityQueue<Integer> endTimes = new PriorityQueue<>();
    for (int[] in : intervals) {
        if (!endTimes.isEmpty() && endTimes.peek() <= in[0]) endTimes.poll(); // reuse a room
        endTimes.offer(in[1]);
    }
    return endTimes.size();
}

Complexity: O(n log n) for both.

Related problems: insert interval, non-overlapping intervals (greedy: sort by end, P46), employee free time. A sweep line (+1 at each start, −1 at each end, sorted) also gives the maximum concurrency, for example “the peak number of concurrent orders per restaurant”.

→

More in Data structures & algorithms

Note 1
The DSA playbook
Note 2
Arrays, hashing & windows
Note 3
Binary search, stacks, heaps & intervals
You're reading this.
Note 4
Linked lists, trees & graphs
Note 5
DP, backtracking & greedy
Note 6
Designing data structures
END OF NOTE 3

Up next: Linked lists, trees & graphs

Short, plain-language notes on what interviewers ask an SDE2 and how to think about it.

Contact