A passing sample test is not the whole test

The sample input passes, you say "done", and the interviewer asks one more question: "What happens on an empty array?" If your first reaction is to look at the code instead of answering, this note is for you. The code is rarely the problem. The problem is a sentence you never said out loud.

The problem

Given an array of integers sorted in non-decreasing order, remove the duplicates in place so that each value appears once, keep the order, and return how many distinct values there are. Only the first positions up to that count matter after the call.

Sample: [1, 1, 2, 3, 3] returns 3, and the array now begins [1, 2, 3].

A solution that passes the sample

static int dedupe(int[] a) {
    int write = 1;                        // a[0] is always kept
    for (int read = 1; read < a.length; read++) {
        if (a[read] != a[write - 1]) {
            a[write++] = a[read];
        }
    }
    return write;
}

Run the sample in your head. write starts at 1. The second 1 equals a[0], skip. 2 differs, so it is written and write becomes 2. 3 differs, written, write is 3. The last 3 equals a[2], skip. The function returns 3. Green.

The input that breaks it

[]. The comment on the second line says "a[0] is always kept", and an empty array has no a[0]. The loop never runs, the function returns 1, and the caller now believes there is one distinct value in an array that holds none. The first read of that value throws.

The bug is not in the loop. It is in the assumption behind the comment: the array has at least one element. The sample never tested that sentence, because whoever wrote the sample had the same sentence in mind.

The fix is one line; the habit is the point

if (a.length == 0) return 0;

Put it before write = 1. Then do the thing that actually changes your interviews: before you say "done", name every assumption the code depends on, and for each one construct the smallest input that violates it. For this function the list is short:

Say it out loud

In the room, the whole thing is two sentences: "I keep the first element, so I am assuming the array is not empty; let me guard that. Everything before write is unique and in order, that is my invariant, and the comparison with a[write - 1] is what keeps it true." Ten seconds. They tell the interviewer you know where the edges of your code are before they have to find them for you.

The exercise

  1. Take the last problem you solved. Write down, one line each, the assumptions your code depends on. Most people find three to five.
  2. For each assumption, write the smallest input that violates it: empty, one element, all equal, already sorted, negative numbers, the largest value the type allows.
  3. Run those inputs by hand before you run them in an editor. Say which ones are outside the problem's contract; that is an answer too.
  4. Keep the one that broke your code. Start your next practice from it.

Where this fits in Gadfly

Step four is the one most people skip, and it is the one Gadfly does for you. In a session the tutor asks about the edge before you declare done, and when something breaks, the session records which assumption it was. The next practice problem is chosen with that record in view, and the reason is named: not "another array problem", but "this one trains the boundary you missed on Tuesday". You code in Java or Python; the tutor never hands over the solution, it asks the next question.

Published 14 October 2026 · One mistake, one counterexample · all notes · feed

This note was drafted by Gadfly's scout — an automated writing agent run by Dmytro Hryshchenko — and checked by rules against the product's claims registry, not read by a person before it went live. The exercise is original. Spotted a mistake? support@usegadfly.com.