Find the two closest of points. Naive is ; three better methods exist.

Method 1: sweep line with a set — the one to write

, about 20 lines, and it reuses std::set.

long long closestPair(vector<P> p) {
    sort(p.begin(), p.end());                          // by x, then y
    set<pair<long long,long long>> box;                // active points, keyed by (y, x)
    long long best = LLONG_MAX;
    int left = 0;
    for (int i = 0; i < (int)p.size(); i++) {
        long long d = (long long)ceil(sqrt((long double)best));
        while (left < i && p[i].x - p[left].x > d) {   // drop points too far left
            box.erase({p[left].y, p[left].x});
            left++;
        }
        auto lo = box.lower_bound({p[i].y - d, LLONG_MIN});
        auto hi = box.upper_bound({p[i].y + d, LLONG_MAX});
        for (auto it = lo; it != hi; ++it)
            best = min(best, norm2(P{(long long)it->second, (long long)it->first} - p[i]));
        box.insert({p[i].y, p[i].x});
    }
    return best;                                        // SQUARED distance
}

Why it is : the active set is a vertical strip of width , and within any window at most 6 points can be pairwise at distance . So each point examines neighbours.

Returning the squared distance keeps everything exact.

Method 2: divide and conquer

Split at the median , recurse, then check the strip of width around the split line, sorted by . The seven-point lemma bounds the strip scan at :

Merge the -orders during the recursion rather than re-sorting. See Bentley-Shamos.

Method 3: randomised incremental — expected

  1. Shuffle the points.
  2. Maintain the best distance and a hash grid with cell size .
  3. Insert points one at a time, checking only the 9 neighbouring cells.
  4. When shrinks, rebuild the grid.
long long closestRandomized(vector<P> p) {
    shuffle(p.begin(), p.end(), rng);
    long long best = norm2(p[1] - p[0]);
    unordered_map<long long, vector<int>> grid;
    long long cell = max(1LL, (long long)sqrt((long double)best));
    auto key = [&](long long x, long long y) { return x * 1000003LL + y; };
    auto rebuild = [&](int upto) {
        grid.clear();
        cell = max(1LL, (long long)sqrt((long double)best));
        for (int i = 0; i < upto; i++) grid[key(p[i].x / cell, p[i].y / cell)].push_back(i);
    };
    rebuild(2);
    for (int i = 2; i < (int)p.size(); i++) {
        long long gx = p[i].x / cell, gy = p[i].y / cell;
        bool shrunk = false;
        for (long long dx = -1; dx <= 1; dx++)
            for (long long dy = -1; dy <= 1; dy++)
                for (int j : grid[key(gx+dx, gy+dy)]) {
                    long long dd = norm2(p[i] - p[j]);
                    if (dd < best) { best = dd; shrunk = true; }
                }
        if (shrunk) rebuild(i + 1);
        else grid[key(gx, gy)].push_back(i);
    }
    return best;
}

The expected total rebuild cost is — the -th point improves the minimum with probability , and a rebuild costs , so the sum telescopes.

Comparison

MethodTimeCodeNotes
Brute force3 linesfine to
Sweep + set~20 linesthe default
Divide and conquer~40 linesclassic; also gives all near pairs
Randomised + grid expected~40 linesfastest, needs a good hash
KD-tree expected~60 linesreusable for other queries
Delaunayvery longthe closest pair is a Delaunay edge

Variants

VariantApproach
Farthest pairit is a hull diameter — rotating calipers
Closest pair in 3Dthe same sweep with a 2D active structure,
Closest pair under / rotate 45° (Manhattan) or sweep directly
Closest pair with insertionsthe randomised grid handles it naturally
All pairs within distance grid buckets of side , then check 9 cells
closest pairsa heap over the candidates found by the sweep
Closest pair between two setsthe same sweep, ignoring same-set pairs

The bucket trick

When the coordinate range is bounded and the answer is expected to be small, a plain grid of side answers “all pairs within ” in . It is the workhorse for collision detection and -body simulation, and often simpler than any of the above.

See also: Bentley-Shamos · Sweep Line · KD-Tree