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
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.
- Make
colGuarded[1..w]androwGuarded[1..h], all false. - For every tower
(x, y), setcolGuarded[x]androwGuarded[y]. - 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.
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.
- Put all tower
xvalues in a list, plus two walls: 0 andw + 1. Sort it. - The free columns between two neighbors
aandbin the sorted list areb - a - 1. Take the biggest. - Do the same with the
yvalues and walls 0 andh + 1. - Multiply the two biggest gaps.
Find the widest and tallest gaps between towers
01 / 06
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
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 andw. Otherwise you lose the edge columns. - Two towers can share a column. The gap between equal numbers is
-1, whichmaxignores, so no special case is needed. - With no towers the answer is
w * h. The walls handle it. w * hcan pass theintrange on some versions. Multiply aslong.
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.