Casework

beginner20 min

The category

Some problems have no single formula. Instead there are a few distinct situations, each with its own answer, and the work is identifying them and handling each correctly.

The risk is not that any one case is hard. It is that you miss one, or that two of your cases overlap and you count something twice.

Enumerate before you code

Write the cases down as a list before writing any code. If you cannot list them, you do not yet understand the problem well enough to implement it.

Three cows stand at distinct positions on a line. In one move, you may take either of the two outer cows and place it at any unoccupied integer position strictly between the other two. What is the maximum number of moves?

Work small examples by hand first.

Working it out

  1. Let the sorted positions be a < b < c. The two gaps are b - a - 1 and c - b - 1 empty spaces.
  2. Each move takes an outer cow into a gap, which shrinks the total space available.
  3. Cases: if both gaps are zero the cows are already adjacent and no move is possible. Otherwise the answer is the larger gap.
int[] p = {a, b, c};
Arrays.sort(p);

int gapLeft  = p[1] - p[0] - 1;
int gapRight = p[2] - p[1] - 1;

if (gapLeft == 0 && gapRight == 0) {
    System.out.println(0);
} else {
    System.out.println(Math.max(gapLeft, gapRight));
}

Sorting first removes three cases immediately — you no longer need separate handling for each possible input order. Normalizing the input is often the cheapest way to collapse casework.

Reduce cases before enumerating them

  • Sort when only relative order matters. Six orderings become one.
  • Take absolute values when only magnitude matters.
  • Swap so that a chosen variable is always the larger. if (x > y) { int t = x; x = y; y = t; } halves symmetric cases.
  • Handle the trivial case first and return, so the main logic does not have to guard against it.

Checking coverage

Two properties are needed. Every input must fall into some case, and no input into two.

Verifying your cases

  1. Complete: take the conditions in order and confirm that anything failing all of them is impossible. An else at the end guarantees completeness if you can argue it is unreachable — or handles the leftover if it is not.
  2. Disjoint: if you used else if throughout, cases cannot overlap by construction. If you used separate if statements that each add to an answer, check overlap deliberately.
  3. Boundaries: for each numeric threshold, test the exact value on both sides. A case split at x < 5 versus x > 5 silently drops x == 5.

The third point is the most frequent failure. Writing if (x < 5) ... else if (x > 5) ... with no branch for equality compiles and runs and is wrong on exactly one input.

Overlapping regions

Two axis-aligned rectangles are given. Print the area covered by at least one of them.

Adding the two areas double-counts the intersection, so subtract it once. That single formula replaces a large amount of casework:

long area1 = (long)(x2 - x1) * (y2 - y1);
long area2 = (long)(x4 - x3) * (y4 - y3);

int overlapW = Math.max(0, Math.min(x2, x4) - Math.max(x1, x3));
int overlapH = Math.max(0, Math.min(y2, y4) - Math.max(y1, y3));
long overlap = (long) overlapW * overlapH;

System.out.println(area1 + area2 - overlap);

The Math.max(0, ...) is what handles the non-overlapping case without a branch. When the rectangles are disjoint the computed width or height is negative, and clamping it to zero makes the overlap zero. Finding an expression that absorbs a case is usually better than adding a branch for it.

This inclusion-exclusion idea generalizes; see Inclusion-Exclusion for the version with many sets.

Structuring the code

Once the cases are listed, write them in the same order, one branch each, with a comment naming the case.

if (n == 0) {
    // no cows: nothing to do
    out.println(0);
} else if (n == 1) {
    // single cow: it is trivially the answer
    out.println(a[0]);
} else if (allEqual(a)) {
    // every cow identical: no move changes anything
    out.println(-1);
} else {
    // general case
    out.println(solve(a));
}

Resist merging branches to make the code shorter. A five-branch if chain that matches your written case list is easier to check against the statement than a clever two-line expression.

Edge cases worth testing on every casework problem

  • N = 0 and N = 1, if the constraints allow them
  • All values identical
  • All values distinct
  • The minimum and maximum legal values
  • Values exactly at each threshold in your conditions
  • Negative values and zero, if permitted
  • Two things at the same position, when the problem involves positions

Practice

For each, list the cases in words before writing code.

  1. Given three side lengths, print whether they form an equilateral, isosceles, scalene, or invalid triangle.
  2. Given two time intervals on a 24-hour clock, print the number of minutes they overlap.
  3. A cow moves along a line, given a starting position and a signed velocity. Given two cows, print whether they ever occupy the same position at the same time, and when.
  4. Given four points, print whether they form an axis-aligned square, a non-square axis-aligned rectangle, or neither.
  5. Given a target integer n, print the minimum number of moves to reach it from 0, where each move adds 1, subtracts 1, or doubles the current value.
Hints
  1. Check validity first — the sum of the two shorter sides must exceed the longest. Then count equal pairs: three equal is equilateral, exactly two is isosceles, none is scalene.
  2. max(0, min(end1, end2) - max(start1, start2)). Same clamping idea as the rectangles.
  3. Equal velocities is a separate case: they meet only if they start at the same position, and then always. Otherwise solve for the meeting time and check that it is non-negative — and whether the problem wants integer times only.
  4. Sort the points. Confirm exactly two distinct x values and two distinct y values, each appearing twice. Square if the two side lengths are equal.
  5. Work backwards from n: halve when even, otherwise move toward the nearest even number. Handle n negative and n == 0 as their own cases first.

Next