−65% Most banks now $169 $59.
Coding · 9 min read

Flexport's 3-Part Shipping Route Coding Question

Flexport wraps a classic range-query problem in its logistics domain: shipping routes with congestion levels that get updated in ranges and queried in ranges. It builds from a difference array to a full lazy segment tree across three parts. Here is the full question, Java for each part, and the rubric.


The question

Shipping routes have congestion levels in an integer array. Traffic updates arrive as (L, R, change), adding change to every route in [L, R].

Part 1: after each update, output all congestion levels. Part 2: answer queries for the minimum congestion in a range [L, R] after updates. Part 3: answer queries for both the minimum and the total congestion in a range.

Part 1 · Range updates, full readout

If you only need the whole array after updates, a difference array applies each range update in O(1) and materializes the array in O(n). Reach for the segment tree only when range queries arrive in Part 2.

class Routes {
    private final long[] diff;     // diff[i] - diff[i-1] reconstructs route i

    Routes(int[] congestion) {
        diff = new long[congestion.length + 1];
        for (int i = 0; i < congestion.length; i++) { diff[i] += congestion[i]; diff[i + 1] -= congestion[i]; }
    }

    void update(int l, int r, int change) { diff[l] += change; diff[r + 1] -= change; }

    long[] snapshot() {
        long[] out = new long[diff.length - 1];
        long run = 0;
        for (int i = 0; i < out.length; i++) { run += diff[i]; out[i] = run; }
        return out;
    }
}

Part 2 · Range-minimum queries

Once you must answer many range-min queries between range updates, a difference array is O(n) per query. A segment tree with lazy propagation does both range add and range min in O(log n). The node stores a min; lazy holds a pending add pushed down on the way through.

class SegTree {
    final int n; final long[] min, lazy;

    SegTree(int[] a) { n = a.length; min = new long[4 * n]; lazy = new long[4 * n]; build(1, 0, n - 1, a); }

    private void build(int node, int lo, int hi, int[] a) {
        if (lo == hi) { min[node] = a[lo]; return; }
        int mid = (lo + hi) >>> 1;
        build(2 * node, lo, mid, a); build(2 * node + 1, mid + 1, hi, a);
        min[node] = Math.min(min[2 * node], min[2 * node + 1]);
    }

    private void apply(int node, long add) { min[node] += add; lazy[node] += add; }
    private void push(int node) { if (lazy[node] != 0) { apply(2*node, lazy[node]); apply(2*node+1, lazy[node]); lazy[node] = 0; } }

    void update(int l, int r, long add) { update(1, 0, n - 1, l, r, add); }
    private void update(int node, int lo, int hi, int l, int r, long add) {
        if (r < lo || hi < l) return;
        if (l <= lo && hi <= r) { apply(node, add); return; }
        push(node); int mid = (lo + hi) >>> 1;
        update(2*node, lo, mid, l, r, add); update(2*node+1, mid+1, hi, l, r, add);
        min[node] = Math.min(min[2*node], min[2*node+1]);
    }

    long queryMin(int l, int r) { return queryMin(1, 0, n - 1, l, r); }
    private long queryMin(int node, int lo, int hi, int l, int r) {
        if (r < lo || hi < l) return Long.MAX_VALUE;
        if (l <= lo && hi <= r) return min[node];
        push(node); int mid = (lo + hi) >>> 1;
        return Math.min(queryMin(2*node, lo, mid, l, r), queryMin(2*node+1, mid+1, hi, l, r));
    }
}

Part 3 · Minimum and sum together

Adding range-sum is not a new structure, just a second aggregate on the same node. A range add of v over k elements increases the sum by v * k, so apply and pull each maintain both fields.

// Add to the node arrays: long[] sum;
// build leaf:   sum[node] = a[lo];
// pull:         sum[node] = sum[2*node] + sum[2*node+1];

private void apply(int node, int lo, int hi, long add) {
    min[node] += add;
    sum[node] += add * (hi - lo + 1);   // every element in the segment shifts by 'add'
    lazy[node] += add;
}

long querySum(int l, int r) { return querySum(1, 0, n - 1, l, r); }
private long querySum(int node, int lo, int hi, int l, int r) {
    if (r < lo || hi < l) return 0;
    if (l <= lo && hi <= r) return sum[node];
    push(node); int mid = (lo + hi) >>> 1;
    return querySum(2*node, lo, mid, l, r) + querySum(2*node+1, mid+1, hi, l, r);
}

Because apply now takes the segment bounds, push and update must pass lo, hi and mid through. The lesson Flexport rewards: pick the lightest structure each part needs, and grow the segment tree by adding aggregates, not rewriting it.

How Flexport scores it

Dimension Weak Strong
Structure choiceSegment tree for everythingDifference array for Part 1, tree only when queries arrive
Lazy propagationForgets to push before recursingCorrect apply, push, and pull
Multiple aggregatesRebuilds for sumAdds a sum field to the same node
ComplexityO(n) per queryO(log n) per update and query
Edge casesBreaks on single route or full rangeHandles boundaries and negative changes
Domain mappingTreats it as abstract array workConnects ranges to routes and congestion

This is one question of 15 pages

Get the full Flexport question bank

The full Flexport bank carries the coding rounds with explicit scoring rubrics, each problem with its parts, compiled from people familiar with the process and cross-verified across sources.

Flexport interview FAQ

What does the Flexport coding interview ask?+

Data-structure problems framed in logistics: range updates and range queries over shipping routes. This one walks from a difference array to a lazy-propagation segment tree supporting range minimum and range sum.

Do Flexport interviews use rubrics?+

Yes. The Flexport bank includes explicit per-question scoring rubrics covering problem understanding, implementation, optimization, testing, and communication, mapped to hire and strong-hire bars.

How hard is the Flexport coding interview?+

The hardest part is the segment tree with lazy propagation. Knowing when a difference array suffices versus when you need a tree, and implementing lazy push and pull correctly, is the differentiator.

Where can I find real Flexport interview questions?+

Pichup maintains a 15-page Flexport question bank compiled from people familiar with the process, with the coding rounds, their parts, and the company's own rubrics. The question in this guide is one of them.