Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 7 – Sorting as a tool

Counting, bucket and radix sort

Sort without comparing: counting sort for small ranges, buckets that find the widest gap in linear time, and LSD radix sort for fixed-width keys.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 6 of 30 minutes free
Free: The problem: the longest quiet spell. With a pass: the other 13 sections and 3 interview answers, about 24 minutes.

What you will learn

  • Sort small-range integers in O(n + k) time with a stable counting sort
  • Find the widest gap between sorted neighbours in O(n) time with buckets
  • Prove with the pigeonhole principle that the widest gap runs between buckets
  • Sort fixed-width keys with LSD radix sort and choose its base
  • Explain why a comparison sort needs about n log₂ n comparisons

Before you start

What you’ll learn · Before you start

What you will learn

  • Sort small-range integers in O(n + k) time with a stable counting sort
  • Find the widest gap between sorted neighbours in O(n) time with buckets
  • Prove with the pigeonhole principle that the widest gap runs between buckets
  • Sort fixed-width keys with LSD radix sort and choose its base
  • Explain why a comparison sort needs about n log₂ n comparisons

Before you start

On this page

Counting sort, bucket sort and radix sort put values in order without ever comparing two of them, which lets them beat the n log n cost of comparison sorts when the values are small integers or keys of fixed width. Counting sort counts how often each value occurs and rebuilds the list from the counts, in O(n + k) time for values from 0 to k. Bucket sort spreads values over ranges of equal width and deals with each range on its own. Radix sort orders fixed-width keys digit by digit, with one stable counting pass per digit, last digit first. This lesson’s problem needs the sorted order of a large log only at its widest gap, and asks for it in linear time.

The problem: the longest quiet spell

The problem

A parcel hub’s scanner records the second at which each parcel passes, times[0..n − 1], in the order the belts report them, which is not time order. The shift manager wants the longest quiet spell: the largest difference between two neighbouring times once the times are in increasing order. Return 0 for fewer than two scans. Limits: 0 ≤ n ≤ 10⁶ and 0 ≤ times[i] ≤ 10⁹, and the solution must run in O(n) time.

  1. [3600, 120, 900, 7200, 1500] gives 3600. In order the times are 120, 900, 1500, 3600 and 7200, and the last two are furthest apart.
  2. [500, 500, 500] gives 0: three parcels in the same second.
  3. [86399, 0] gives 86399.
A time line with the scans 120, 900, 1500, 3600 and 7200; their gaps are 780, 600, 2100 and 3600, and 3600 is the longest.12090015003600720078060021003600, the longestScan times in order, with each gapseconds after the start of the shift

The first example in time order

Text description of the diagram

A horizontal time line, in seconds after the start of the shift, carries five dots, one per scan of the first example, at 120, 900, 1500, 3600 and 7200.

A bracket above each pair of neighbours gives the gap between them: 780 from 120 to 900, 600 from 900 to 1500, 2100 from 1500 to 3600, and 3600 from 3600 to 7200. The last bracket is drawn thicker and labelled as the longest, so the answer for this log is 3600 seconds.

The brute force, and why sorting is not allowed

For every scan, look through all the scans for the next later time, and keep the largest difference. That is exactly n² steps: 4,000,000 for 2,000 scans and 10¹² for a million. Sorting first and comparing neighbours is fast in practice, but it breaks the stated limit, and the run shows why no comparison sort can meet it:

Every scan against every scan, and what sorting costs Python · brute/gap_brute.py
# The longest quiet spell by brute force: for each scan, look through every scan for the next later time.
# Then the cost of the usual fix, sorting first, and the least any comparison sort can do.
import math
import random


def longest_gap_brute(times):
    """Returns the largest gap between consecutive times in sorted order, and the steps taken: exactly n * n."""
    steps = 0
    best = 0
    for t in times:
        following = None  # the smallest time later than t
        for u in times:
            steps += 1
            if u > t and (following is None or u < following):
                following = u
        if following is not None:
            best = max(best, following - t)
    return best, steps


for times in ([3600, 120, 900, 7200, 1500], [500, 500, 500], [86399, 0]):
    print(times, "->", longest_gap_brute(times)[0])

rng = random.Random(3)
for n in (1_000, 2_000):
    _, steps = longest_gap_brute([rng.randint(0, 10**9) for _ in range(n)])
    print(f"n = {n:,}: {steps:,} steps")
print(f"n = 1,000,000: {10**12:,} steps")


class Counted:
    """A time that counts how often sorted() compares it with another (sorted() only uses <)."""
    comparisons = 0

    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        Counted.comparisons += 1
        return self.value < other.value


sorted(Counted(rng.randint(0, 10**9)) for _ in range(100_000))
print(f"sorting 100,000 times: {Counted.comparisons:,} comparisons")
bound = math.ceil(math.lgamma(1_000_001) / math.log(2))
print(f"any comparison sort, 1,000,000 distinct times: at least {bound:,} comparisons on its worst input")

Output

[3600, 120, 900, 7200, 1500] -> 3600
[500, 500, 500] -> 0
[86399, 0] -> 86399
n = 1,000: 1,000,000 steps
n = 2,000: 4,000,000 steps
n = 1,000,000: 1,000,000,000,000 steps
sorting 100,000 times: 1,532,014 comparisons
any comparison sort, 1,000,000 distinct times: at least 18,488,885 comparisons on its worst input

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 gap_brute.py

Python’s sort compared 1,532,014 pairs for 100,000 times, close to n log₂ n. That is no quirk of one library. A sort that only compares must tell apart all n! orders of n different values, and each comparison has two outcomes, so some input needs at least log₂ n! comparisons: 18,488,885 for a million times. Linear time means not comparing the times with each other at all.

What to notice

The times are integers in a known range, so a time can serve as an address, the way counting sort uses each value. And the widest gap is never narrower than the average gap: the n − 1 gaps between neighbours add up to the largest time minus the smallest, so at least one of them is that wide. Two times that are closer together than the average gap can never be the two ends of the answer.

Buckets narrower than the average gap Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why the widest gap always runs between buckets: the pigeonhole proof
  • A dry run on the first example
  • The code in Python, JavaScript, Java, C++ and Go
    • Three slips, caught by a stress test
  • Counting sort, measured on a million exam marks
  • LSD radix sort for fixed-width keys
  • Choosing among the three
  • Edge cases and common bugs
  • Variants, with answers
  • Follow-up questions, answered
  • Exercise and practice set
    • Find the widest gap in sorted order, without sorting
  • Check yourself
  • Interview questions
    • When is counting sort a poor choice, even though it runs in O(n + k)?
    • A service must sort 10⁸ passenger ages, each from 0 to 120, held in a byte array, with only 20 MB of extra memory and a two-second budget. A teammate proposes the language's built-in sort. What do you propose, and what does it cost in time and memory?
    • You found the widest gap between sorted neighbours in O(n) with buckets. The interviewer asks why the answer can never lie inside a bucket, why each bucket keeps only its minimum and maximum, and what changes for real numbers.
    • Sort 10⁷ ten-digit mobile numbers held as 64-bit integers, as fast as you can. Built-in sort, counting sort or radix sort? If radix sort, which base, how many passes, and why must each pass be stable?
  • Key takeaways

1 diagram · 5 runnable examples (Build and run all three, C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 25 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.