The problem in brief
Meteorites fly away from the station roughly along one straight line. Ray bumped the gravitational matrix several times, and each bump knocked a meteorite off that common line by more than 40 %. You get the coordinates of all meteorites, with for every one of them, and must print the ids of the knocked-off ones. In machine-learning terms this is outlier detection with a robust regression: find the line that the majority follows, then flag the points that disagree with it.
How you are scored
Hidden tests compare the printed set of ids with the true set (time limit 1 s). The statement gives neither a sample nor a precise definition of "deviates by more than 40 %", so we have to commit to a reading and test it on our own simulated data:
- the common line is (the coordinate carries no information);
- a meteorite deviates by more than 40 % when its relative deviation exceeds 0.4:
We score our method by the share of simulated tests where the printed id set is exactly right.
A first baseline
Fit the line by ordinary least squares on all points, then flag every point with . It works when nothing is wrong (100 % of tests without outliers) and degrades quickly: 83 % exact with 20 % of knocked-off meteorites, 51 % with 45 %.
The reason is visible in the figure. Least squares minimises , and a point 150 units away weighs as much as points that are 1 unit away. If the bumps push meteorites mostly in one direction, the fitted line is dragged towards them, good meteorites end up outside the band and bad ones inside it. The method uses the outliers to define "normal", which defeats its own purpose.

The key idea
Fit the line with a statistic that outliers cannot move: the median. Least median of squares (LMedS) chooses the line that minimises the median residual instead of the sum:
As long as fewer than half of the points are outliers, the median residual is decided by good points only: moving an outlier, even to infinity, does not change it. Statisticians say that LMedS has a breakdown point of 50 %, against 0 % for least squares, where a single point can move the line arbitrarily far.
The minimisation has no formula, but a candidate line only needs two points. So:
- pick a random pair of meteorites, take the line through them, compute the median of over all points;
- repeat for 400 random pairs (or all pairs when ), keep the line with the smallest median;
- refit by least squares on the points within 40 % only (more accurate than a line through 2 points), repeat the selection twice;
- print the ids with .
Why are 400 pairs enough? If a fraction of points are outliers, a random pair is "clean" with probability , and all 400 draws miss a clean pair with probability . Even with , that is . This sampling argument is the same as in RANSAC, the workhorse of computer vision for fitting models in data full of outliers.
A remark on : writing points as is the trick of homogeneous coordinates. A line becomes , and the line through two points is the cross product of their homogeneous vectors. It is elegant (and handles vertical lines), but with the relative-deviation reading above, the slope-intercept form is simpler, so we stay with it.
The full solution
def lmeds_line(xs, ys, trials=400):
best = (float("inf"), 0.0, 0.0)
for _ in range(trials):
i, j = rng.sample(range(n), 2)
if xs[i] == xs[j]:
continue
a = (ys[j] - ys[i]) / (xs[j] - xs[i]); b = ys[i] - a * xs[i]
med = sorted(rel_dev(a, b, x, y) for x, y in zip(xs, ys))[n // 2]
if med < best[0]:
best = (med, a, b)
return best[1], best[2]
Then find_outliers refits by least squares on the points with and prints the others. Everything is pure Python: 400 trials over 1000 points take about 0.2 s. A fixed random seed makes the output reproducible.
Simulated tests (solution.py --bench): 10 to 300 points on a random line kept away from (so that relative deviations are meaningful), good meteorites with noise, a chosen share of knocked-off meteorites with relative deviations between 45 % and 200 %, in either direction; 150 tests per outlier share.
Results
Share of simulated tests with the exact id set:
| share of knocked-off meteorites | 0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.45 |
|---|---|---|---|---|---|---|
| least squares, then threshold | 1.000 | 0.940 | 0.827 | 0.687 | 0.580 | 0.507 |
| LMedS + least-squares refit on inliers | 1.000 | 1.000 | 1.000 | 1.000 | 0.973 | 0.947 |
The few LMedS misses at 40 to 45 % come from tests where, by chance, the knocked-off meteorites are close to half of the points: then even the median is no longer protected. Beyond 50 % the problem itself becomes ill-posed, since the "common line" is no longer the majority.
Honest caveat: the official tests are hidden and the statement is vague, so the exact definition of "40 %" (relative to , to the distance from the line, or to something else) is our interpretation. The robust-fitting part of the solution does not depend on it; only the final rel_dev function would change.
What to remember
- Least squares is not robust: one far point can move the fit anywhere, so never detect outliers with a model fitted on the outliers.
- The median resists contamination up to 50 %: least median of squares fits the majority, whatever the minority does.
- Fit from minimal random samples (two points for a line) and keep the best by a robust score: this is RANSAC, used everywhere in vision (image stitching, 3-D reconstruction).
- Refit on the inliers once they are known: robustness first, then precision.
- When a statement is vague, state your interpretation and isolate it in one function, so that changing your reading is a one-line edit.