Skip to content
dsa450for five year olds

Greedy · 25 of 35

DEFKIN - Defense of a Kingdom

Towers guard their whole row and column, and you find the biggest field that no tower can see by looking for the widest and tallest gaps.

Simple way
time O(w + h + k)
room O(w + h)
Clever way
time O(k log k)
room O(k)

The problem, simply

A kingdom is a grid w columns wide and h rows tall. There are k towers, each standing on one cell (x, y). A tower guards every cell in its column and every cell in its row.

Give back the area of the biggest rectangle of cells that no tower guards. (This is SPOJ DEFKIN.)

A story to remember it

Picture it

gridkingdom
12345678123456TT

An 8 by 6 kingdom. T marks a tower. Each tower guards its whole row and its whole column.

  • rejected

Examples

A normal case

In
w = 8, h = 6, towers (2, 4) and (5, 1)
Out
6

Columns 6 to 8 are free (3 wide) and rows 2 to 3 are free (2 tall). 3 x 2 = 6.

The SPOJ sample

In
w = 15, h = 8, towers (3, 8), (11, 2), (8, 6)
Out
12

Widest free columns: 4 (columns 4 to 7, or 12 to 15). Tallest free rows: 3 (rows 3 to 5). 4 x 3 = 12.

No towers

In
w = 5, h = 5, no towers
Out
25

Everything is free.

Every column guarded

In
w = 1, h = 1, tower (1, 1)
Out
0

The only cell has a tower on it.

Two towers in one column

In
w = 4, h = 4, towers (2, 1) and (2, 4)
Out
4

Free columns: 1, and 3 to 4 (2 wide). Free rows: 2 to 3 (2 tall). 2 x 2 = 4.

Way 1: the simple way

Draw the map. Mark every guarded column and every guarded row. Then walk the columns and find the longest run of unmarked ones, and do the same for the rows.

  1. Make colGuarded[1..w] and rowGuarded[1..h], all false.
  2. For every tower (x, y), set colGuarded[x] and rowGuarded[y].
  3. Find the longest run of free columns and the longest run of free rows. Multiply them.

Why can you multiply? A free run of columns and a free run of rows always cross in a block where no cell shares a row or column with a tower.

java
class Solution {
    public long largestUndefended(int w, int h, int[][] towers) {
        boolean[] colGuarded = new boolean[w + 1];
        boolean[] rowGuarded = new boolean[h + 1];
        for (int[] t : towers) {
            colGuarded[t[0]] = true;     // the tower sees its column
            rowGuarded[t[1]] = true;     // and its row
        }
        return (long) longestFree(colGuarded, w) * longestFree(rowGuarded, h);
    }

    private int longestFree(boolean[] guarded, int n) {
        int best = 0, run = 0;
        for (int i = 1; i <= n; i++) {
            run = guarded[i] ? 0 : run + 1;
            best = Math.max(best, run);
        }
        return best;
    }
}

How long it takes: one pass over the towers, columns and rows, O(w + h + k). Extra room: the two marks arrays, O(w + h). Fine for a 40,000 wide kingdom, but useless if w could be a billion.

Way 2: the clever way

You do not need the whole map, only where the towers stand.

  1. Put all tower x values in a list, plus two walls: 0 and w + 1. Sort it.
  2. The free columns between two neighbors a and b in the sorted list are b - a - 1. Take the biggest.
  3. Do the same with the y values and walls 0 and h + 1.
  4. Multiply the two biggest gaps.

Find the widest and tallest gaps between towers

01 / 06

gridkingdom
12345678123456TT

An 8 by 6 kingdom with two towers: one at column 2, row 4, and one at column 5, row 1.

towers
2
  • answer
  • rejected
  • path
  • ignored
java
class Solution {
    public long largestUndefended(int w, int h, int[][] towers) {
        int k = towers.length;
        int[] xs = new int[k + 2], ys = new int[k + 2];
        xs[0] = 0; xs[k + 1] = w + 1;          // the two walls
        ys[0] = 0; ys[k + 1] = h + 1;
        for (int i = 0; i < k; i++) {
            xs[i + 1] = towers[i][0];
            ys[i + 1] = towers[i][1];
        }
        Arrays.sort(xs);
        Arrays.sort(ys);
        return (long) biggestGap(xs) * biggestGap(ys);
    }

    private int biggestGap(int[] sorted) {
        int best = 0;
        for (int i = 1; i < sorted.length; i++) {
            best = Math.max(best, sorted[i] - sorted[i - 1] - 1);  // free lines strictly between
        }
        return best;
    }
}

How long it takes: two sorts of k + 2 numbers, O(k log k). Extra room: the two lists, O(k).

Watch out for

  • Add the walls at 0 and w + 1, not at 1 and w. Otherwise you lose the edge columns.
  • Two towers can share a column. The gap between equal numbers is -1, which max ignores, so no special case is needed.
  • With no towers the answer is w * h. The walls handle it.
  • w * h can pass the int range on some versions. Multiply as long.

What interviewers ask next

  • Why are rows and columns independent? A cell is safe exactly when its column is free and its row is free. So a rectangle is safe exactly when all its columns and all its rows are free.
  • What if a tower only guarded nearby cells? Then the independence breaks, and you need the maximal rectangle in a binary matrix: histogram plus a stack, O(w * h).
  • Towers are added one at a time and you must answer after each? Keep sorted sets of tower columns and rows plus a multiset of gaps. Each insert splits one gap into two, O(log k).
  • Same trick elsewhere: "Maximum area of a piece of cake after horizontal and vertical cuts" (LeetCode 1465) is this problem with cut lines instead of towers.

Remember this

Grown-up words: the seekers are towers that block a full row and column, the free runs are gaps between sorted coordinates, and the walls at 0 and w + 1 are sentinels.