Domino & Tromino

Domino & Tromino Tiling – DP Jugaad

Problem Statement

You're given a 2 x n board and infinite supplies of:

  • 2×1 dominoes (can be placed vertically or horizontally)

  • “L” shaped trominoes (covers three tiles in an "L" pattern)

Your mission (should you choose to accept it): Count the number of ways to completely tile the board using these pieces.
Return the count modulo 10⁹ + 7 because math is wild and the numbers explode .

Example

Let’s take n = 3

Output: 5

Explanation:

  1. 3 vertical dominoes

  2. 1 horizontal domino + 2 verticals

  3. 1 L-shaped tromino

  4. 1 flipped L-shaped tromino

  5. 2 L-shaped trominoes

Basically, there are 5 funky but valid ways to tile this thing.

Best Data Structure for the Job

A 1D array for dynamic programming is all you need.
No need for fancy data structures – just solid DP logic and some good old pattern recognition.

Different Approaches

Approach 1: Brute Force (Educational but Painfully Slow )

You can try all possible tile placements recursively... until your computer begs for mercy.
Use this only for n <= 4 if you're into recreational suffering.


public class BruteForceTiling { public int countWays(int n) { if (n == 0) return 1; if (n == 1) return 1; if (n == 2) return 2; return countWays(n - 1) + countWays(n - 2) + 2 * countWays(n - 3); } }

Warning: This becomes exponential fast. Your laptop might start crying.

Approach 2: Optimized DP 

We use a recurrence relation that captures all valid tile placements at position i.

Let:

  • dp[i] = number of ways to tile a 2 x i board

  • preSum[i] = running sum of previous dp values for tromino contributions

  • The efficient form: (2 * dp[i - 1] + dp[i - 3])

Recurrence Relation:


dp[i] = dp[i - 1] + dp[i - 2] + 2 * preSum[i - 3] preSum[i] = dp[0] + dp[1] + ... + dp[i]

public class DominoTiling { public int numTilings(int n) { int MOD = 1_000_000_007; if (n == 0) return 1; if (n == 1) return 1; if (n == 2) return 2; long[] dp = new long[n + 1]; long[] preSum = new long[n + 1]; dp[0] = 1; dp[1] = 1; dp[2] = 2; preSum[0] = 1; preSum[1] = 2; preSum[2] = 4; for (int i = 3; i <= n; i++) { dp[i] = (dp[i - 1] + dp[i - 2] + 2 * preSum[i - 3]) % MOD; preSum[i] = (preSum[i - 1] + dp[i]) % MOD; } return (int) dp[n]; } }

⚠️ Common Mistakes and Pitfalls

  •  Forgetting base cases like n = 0, 1, and 2

  •  Ignoring the 2 * preSum[i - 3] term from trominoes

  •  Mismanaging modular arithmetic and ending up with overflow errors

  •  Trying to visualize n = 10 cases by hand... save yourself 

📊 Time and Space Complexity Analysis

Approach      Time Complexity     Space Complexity
Brute Force      Exponential          O(n) (stack)
DP Optimized      O(n)         O(n)

🌍 Real-world Applications

  • Game board tile placements (Tetris feels)

  • Puzzle generation using shape constraints

  • Structural tiling in floor planning and design

  •  AI bots planning tile-based level strategies


I hope you found this article insightful! Keep exploring, keep learning, and don’t forget to check back daily for more exciting problem breakdowns. If you know someone who would benefit from this, share it with them and help them grow too! That’s it for today—see you in the next post!

                                                                                                                                         Signing off!! 

                                                                                                Master DSA One Problem at a Time :)

Comments

Popular posts from this blog

Trailing Zeros in Factorial – How Many and Why?

Divisible Drama — Who’s In, Who’s Out?

Zero Array After Queries