DP - 1D · Medium
LeetCode 790: Domino and Tromino Tiling — solution
Two-state DP: count full tilings and tilings with one cell sticking out, then combine them. O(n) time and O(1) space, everything taken modulo 10^9 + 7.
Problem in plain words
You have a board that is 2 cells tall and n cells wide. You may use two kinds of pieces as many times as you like: a 2x1 domino and an L-shaped tromino (three cells), and both may be rotated. Count the ways to cover the whole board with no gaps or overlaps, and return the count modulo 1_000_000_007.
For a 2x2 board there are 2 ways (two vertical dominoes, or two horizontal ones). Trominoes first appear at width 3, which has 5 tilings in total.
Intuition
Fill the board from left to right and look at the shape of the right edge. It is either flat (both rows end at the same column) or jagged (one row sticks out by one cell). A tromino is the only piece that can create or close a jagged edge. So track two counts:
full[i]: ways to cover exactly the firsticolumns.part[i]: ways to cover the firsti - 1columns plus the top cell of columnionly. By symmetry the bottom version has the same count.
Each count is built from smaller widths, exactly like the bottom-up Fibonacci DP lesson but with two interleaved sequences.
Approach
- Recurrence for full: the last piece placed on a flat edge is either one vertical domino (
full[i - 1]), two stacked horizontal dominoes (full[i - 2]), or a tromino that closes a jagged edge from widthi - 1, which can be top or bottom (2 * part[i - 1]). Sofull[i] = full[i - 1] + full[i - 2] + 2 * part[i - 1]. - Recurrence for part: a jagged edge at column
icomes either from a tromino laid on a flat edge of widthi - 2(full[i - 2]), or from a horizontal domino extending the opposite jagged edge of widthi - 1(part[i - 1]). Sopart[i] = part[i - 1] + full[i - 2]. - Base cases:
full[0] = 1(the empty board),full[1] = 1,part[0] = part[1] = 0. - Order: compute
i = 2ton, taking every sum modulo 10^9 + 7. Returnfull[n].
Dry run
| i | full[i] | part[i] |
|---|---|---|
| 0 | 1 | 0 |
| 1 | 1 | 0 |
| 2 | 1 + 1 + 2*0 = 2 | 0 + 1 = 1 |
| 3 | 2 + 1 + 2*1 = 5 | 1 + 1 = 2 |
| 4 | 5 + 2 + 2*2 = 11 | 2 + 2 = 4 |
| 5 | 11 + 5 + 2*4 = 24 | 4 + 5 = 9 |
Java solution
class Solution {
public int numTilings(int n) {
final long MOD = 1_000_000_007L;
if (n <= 1) return 1;
long[] full = new long[n + 1];
long[] part = new long[n + 1];
full[0] = 1;
full[1] = 1;
for (int i = 2; i <= n; i++) {
full[i] = (full[i - 1] + full[i - 2] + 2 * part[i - 1]) % MOD;
part[i] = (part[i - 1] + full[i - 2]) % MOD;
}
return (int) full[n];
}
}Python solution
class Solution:
def numTilings(self, n: int) -> int:
MOD = 10**9 + 7
if n <= 1:
return 1
full = [0] * (n + 1)
part = [0] * (n + 1)
full[0] = full[1] = 1
for i in range(2, n + 1):
full[i] = (full[i - 1] + full[i - 2] + 2 * part[i - 1]) % MOD
part[i] = (part[i - 1] + full[i - 2]) % MOD
return full[n]Complexity
| Measure | Cost | Why |
|---|---|---|
| Time | O(n) | Two constant-time updates per column. |
| Space | O(n) | Two arrays; easily reduced to O(1) with rolling variables since only the last two widths are used. |
Edge cases and common mistakes
- n = 1: only one vertical domino fits, so the answer is 1. Guard it before indexing
full[2]-style arrays. - Forgetting the factor 2: a jagged edge can stick out on top or on bottom; counting only one side gives 4 instead of 5 for n = 3.
- Overflow in Java:
2 * part[i - 1]onintvalues near the modulus overflows. Uselong. - Applying the modulus only at the end: intermediate values grow exponentially, so reduce at every step.
›Is there a single-sequence formula?
Yes. Substituting the part recurrence into full gives full[n] = 2 * full[n - 1] + full[n - 3] for n >= 3. Check it: 2 * 5 + 1 = 11 and 2 * 11 + 2 = 24. The two-state version is easier to derive in an interview.
