Unit 1 · Algorithms · Lesson 6 of 24
Sorting and binary search
Builds on
Step 1: Learn the ideas
- Comparison sorts: merge sort, quicksort, heap sort, insertion sort
- Comparison lower bound and decision trees
- Stability, comparators and multi-key sorting
- Counting sort and radix sort for bounded keys
- Sorting as preprocessing
- Binary search with half-open intervals: lower and upper bound
- Binary search on a monotone predicate (search on the answer)
- Rotated arrays, peaks and implicit search spaces
- Partitioning and quickselect
Why it matters
Sorted data makes many questions easy: duplicates become neighbors, pairs can be found with two pointers, intervals merge in one pass and lookups take O(log n). Binary search is how you exploit order, and its general form, finding the first point where a monotone condition becomes true, solves optimization problems that do not look like searching at all. Both are classic places for interviewers to check off-by-one discipline and whether you can state an invariant.
Core ideas
Sorting algorithms. Merge sort is Θ(n log n) in the worst case, stable, and uses O(n) extra space. Quicksort is O(n log n) expected with random pivots but O(n²) in the worst case, and in place apart from its recursion. Heap sort is O(n log n) worst case and in place but not stable. Insertion sort is O(n²) yet fast on tiny or nearly sorted inputs, which is why hybrid library sorts use it for small runs. Library sorts are hybrids; know whether yours is stable (Python, Java object sorts and JavaScript are; C++ std::sort is not).
The lower bound. A comparison sort must distinguish all n! input orders, and a binary decision tree with n! leaves has height at least log₂(n!) = Θ(n log n). Counting sort (O(n + k) for keys in a range of size k) and radix sort escape the bound because they use key values, not just comparisons.
Pattern: Sorting as preprocessing. If the answer does not depend on input order, sort first and pay O(n log n): 3Sum, Merge Intervals, meeting-room overlaps and many greedy problems start this way. Ask whether reordering is allowed; if original indices matter, sort (value, index) pairs.
Pattern: Binary search on a sorted space. Use an explicit invariant:
lo, hi = 0, len(a) # invariant: the answer index lies in [lo, hi]
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < target: # a[mid] and everything left of it are too small
lo = mid + 1
else: # mid itself may be the answer
hi = mid
return lo # first index with a[i] >= target, or len(a)
This is lower_bound; changing < to <= gives upper_bound, the first index with a[i] > target, and the count of target values is their difference. Every iteration shrinks the interval, so the loop terminates, and when it ends lo is the boundary. In fixed-width languages compute the midpoint as lo + (hi - lo) / 2 to avoid overflow.
Pattern: Binary search on the answer. Binary search needs a predicate that is false and then true across an ordered search space, not a sorted array. In Koko Eating Bananas, "all piles can be finished within h hours at speed s" is monotone in s, so you search for the smallest feasible s between 1 and the largest pile, checking each candidate in O(n): O(n log max) in total. Write the predicate first, argue monotonicity, then choose bounds that surely contain the answer.
Implicit search spaces. In a rotated sorted array with distinct values, one half around mid is always sorted; check whether the target lies inside that half and discard the other. For a peak, comparing a[mid] with a[mid + 1] tells you which side must contain one. A row-major sorted matrix is a sorted array of length rows × cols.
Common misconceptions
- "Binary search needs a sorted array." It needs a monotone predicate over an ordered space; a sorted array is one example.
- "Quicksort is O(n log n)." Only in expectation with random pivots; a simple deterministic pivot rule (first, last or middle element) has inputs that force O(n²).
- "Any comparator works." A comparator must define a consistent ordering; inconsistent ones give wrong output, runtime errors or, in C++, undefined behavior.
- "Stability is irrelevant." It matters whenever you sort by one key after another or need ties to keep input order.
- "
lo <= hiorlo < hiis a matter of taste." Each form needs matching updates and a matching meaning for the final index; mixing them causes infinite loops or skipped answers.
How to approach it
Ask whether sorting is allowed and add its cost to the total. For binary search, write the invariant as a comment before the loop and say what lo means at the end. Test an empty array, one element, all-equal elements and targets below and above the range. Interviewers probe boundary handling, the monotonicity argument in search-on-answer problems, and, at deeper levels, quicksort's worst case, stability and the lower bound.
Suggested order
- 1Read MIT 6.006 Lecture 3 (Sorting) and Recitation 3 for insertion, selection and merge sort, stability, in-place sorting and recurrences.
- 2Read MIT 6.006 Lecture 5 (Linear Sorting) and Recitation 5 for the decision-tree lower bound, counting sort and radix sort.
- 3Read the algs4 Quicksort section (2.3) for random shuffling, partitioning and three-way partitioning with duplicate keys.
- 4Write lower_bound and upper_bound from scratch with a half-open interval and test them on empty, single-element, all-equal and out-of-range inputs.
- 5Solve Binary Search, Search Insert Position and Find First and Last Position of Element in Sorted Array with the same function.
- 6Solve Search in Rotated Sorted Array and Find Peak Element, stating which half is safe to discard at each step.
- 7Solve Koko Eating Bananas and Capacity To Ship Packages Within D Days by writing and testing the feasibility predicate first.
- 8Implement merge sort for Sort an Array and a three-way partition for Sort Colors; keep Median of Two Sorted Arrays for later review.
Step 2: Check off what you can do
Tap each one you can genuinely do or explain. Each earns 10 XP.
Step 3: Go deeper
MIT 6.006 Introduction to Algorithms (Spring 2020)Start here
MIT OpenCourseWareSection: Lecture 3: Sorting
Insertion, selection and merge sort, in-place sorting and stability, and recurrences; Recitation 3 adds sorted-array sets and the master theorem.
Open(opens in a new tab)Link responded, 5 Oct 2026MIT 6.006 Introduction to Algorithms (Spring 2020)
MIT OpenCourseWareSection: Lecture 5: Linear Sorting
The comparison lower bound and how counting and radix sort avoid it; Recitation 5 has worked code.
Open(opens in a new tab)Link responded, 5 Oct 2026Algorithms, 4th Edition booksite: sorting, searching and trie sections
Princeton UniversitySection: 2.3 Quicksort
Random shuffling, partitioning invariants and three-way partitioning for inputs with many duplicate keys.
Open(opens in a new tab)Link responded, 5 Oct 2026Competitive Programmer’s Handbook: search, amortized-analysis, range-query and trie sections
CSESSection: Ch. 3: Sorting (3.3 Binary search)
Short binary-search implementations, including finding the first position where a condition becomes true.
Open(opens in a new tab)Link responded, 5 Oct 2026Go documentation: slices, maps, sort and container/heap
The Go Authors (go.dev)Section: sort.Search
A standard-library binary search over a monotone predicate; a clean model for search on the answer whatever language you use.
Open(opens in a new tab)Link responded, 5 Oct 2026
Step 4: Practice
Use one invariant-based template for every binary-search variant and write the invariant as a comment before coding; when a variant fails, record which boundary case broke it. For search-on-answer problems, write and test the feasibility predicate on its own before adding the search. Sort an Array is for implementing merge sort or heap sort yourself; Median of Two Sorted Arrays is a hard review problem on searching a partition position.
- Binary SearchLeetCode(opens in a new tab)Not attemptedLeetCode
- Search Insert PositionLeetCode(opens in a new tab)Not attemptedLeetCode
- Find First and Last Position of Element in Sorted ArrayLeetCode(opens in a new tab)Not attemptedLeetCode
- Search in Rotated Sorted ArrayLeetCode(opens in a new tab)Not attemptedLeetCode
- Find Peak ElementLeetCode(opens in a new tab)Not attemptedLeetCode
- Koko Eating BananasLeetCode(opens in a new tab)Not attemptedLeetCode
- Capacity To Ship Packages Within D DaysLeetCode(opens in a new tab)Not attemptedLeetCode
- Sort ColorsLeetCode(opens in a new tab)Not attemptedLeetCode
- Sort an ArrayLeetCode(opens in a new tab)Not attemptedLeetCode
- Median of Two Sorted ArraysLeetCode(opens in a new tab)Not attemptedLeetCode
- Find Minimum in Rotated Sorted ArrayLeetCode(opens in a new tab)Not attemptedLeetCode
- Largest NumberLeetCode(opens in a new tab)Not attemptedLeetCode
- Search a 2D MatrixLeetCode(opens in a new tab)Not attemptedLeetCode
- Time Based Key-Value StoreLeetCode(opens in a new tab)Not attemptedLeetCode
Record attempts on each problem’s page (+15 XP, +10 more when solved on your own).
Step 5: Test yourself
Answer each one out loud or on paper before you finish the lesson.
- Question 1What invariant does your binary-search loop maintain, and what does the final index mean?
- Question 2How do you choose the bounds when searching on an answer?
- Question 3When is a stable sort required?
- Question 4Why is quicksort’s worst case quadratic, and how does randomization help?
- Question 5In a rotated sorted array, how do you know which half is sorted?
- Question 6What breaks when the rotated array contains duplicates?
You’re done when you can
- Write lower_bound and upper_bound from memory with correct boundaries on the first attempt.
- Solve one unseen search-on-answer problem in under 25 minutes, including the monotonicity argument.
- Explain why the comparison lower bound does not apply to counting sort.
- Implement merge sort and state its time, extra space and stability.
Finish the lesson
Unlocks next: Prefix sums, intervals and sweep lines, Greedy algorithms and exchange arguments, Divide and conquer


