Tiling Problem (original) (raw)

Last Updated : 16 Dec, 2024

Try it on GfG Practice redirect icon

Given a "2 x n" board and **tiles of size "2 x 1", the task is to **count the number of ways to tile the given board using the **2 x 1 tiles. A tile can either be placed **horizontally i.e., as a 1 x 2 tile or **vertically i.e., as 2 x 1 tile.

**Examples:

**Input: n = 4
**Output: 5
**Explanation: For a 2 x 4 board, there are 5 ways

Tile

**Input: n = 3
**Output: 3
**Explanation: We need 3 tiles to tile the board of size 2 x 3.
We can tile the board using the following ways

Board

Table of Content

Using Recursion - O(2^n) Time and O(n) Space

The idea is to explore **two possible ways to place tiles on a **2 x n board: either placing a **vertical tile (2 x 1) which reduces the problem to filling a 2 x (n-1) board, or placing **two horizontal tiles (1 x 2) which reduces the problem to filling a **2 x (n-2) board. At each step, we **sum these two possibilities, creating a recursive solution where the total number of ways to tile the board is the sum of ways for the smaller subproblems.

Mathematically the recurrence relation will look like the following:

**numberOfWays(n) = numberOfWays(n-1) + numberOfWays(n-2).

**Base Cases:

C++ `

// C++ program to implement // tiling problem using recursion #include <bits/stdc++.h> using namespace std;

int numberOfWays(int n) {

// Base Case: invalid n 
if (n<0) return 0;

// Base case: valid n 
if (n == 0) return 1;

int ans = 0;

// count ways if one tile 
// is placed vertically
ans = numberOfWays(n-1);

// count ways if two tiles 
// are placed horizontly.
ans += numberOfWays(n-2);

return ans;

}

int main() { int n = 4; cout<<numberOfWays(n);

return 0;

}

Java

// Java program to implement // tiling problem using recursion

class GfG {

static int numberOfWays(int n) {
    
    // Base Case: invalid n 
    if (n < 0) return 0;
    
    // Base case: valid n 
    if (n == 0) return 1;
    
    int ans = 0;
    
    // count ways if one tile 
    // is placed vertically
    ans = numberOfWays(n - 1);
    
    // count ways if two tiles 
    // are placed horizontally.
    ans += numberOfWays(n - 2);
    
    return ans;
}

public static void main(String[] args) {
    int n = 4;
    System.out.println(numberOfWays(n));
}

}

Python

Python program to implement

tiling problem using recursion

def numberOfWays(n):

# Base Case: invalid n 
if n < 0:
    return 0

# Base case: valid n 
if n == 0:
    return 1

ans = 0

# count ways if one tile 
# is placed vertically
ans = numberOfWays(n - 1)

# count ways if two tiles 
# are placed horizontally.
ans += numberOfWays(n - 2)

return ans

if name == "main": n = 4 print(numberOfWays(n))

C#

// C# program to implement // tiling problem using recursion

using System;

class GfG {

static int numberOfWays(int n) {
    
    // Base Case: invalid n 
    if (n < 0) return 0;
    
    // Base case: valid n 
    if (n == 0) return 1;
    
    int ans = 0;
    
    // count ways if one tile 
    // is placed vertically
    ans = numberOfWays(n - 1);
    
    // count ways if two tiles 
    // are placed horizontally.
    ans += numberOfWays(n - 2);
    
    return ans;
}

static void Main(string[] args) {
    int n = 4;
    Console.WriteLine(numberOfWays(n));
}

}

JavaScript

// JavaScript program to implement // tiling problem using recursion

function numberOfWays(n) {

// Base Case: invalid n 
if (n < 0) return 0;

// Base case: valid n 
if (n === 0) return 1;

let ans = 0;

// count ways if one tile 
// is placed vertically
ans = numberOfWays(n - 1);

// count ways if two tiles 
// are placed horizontally.
ans += numberOfWays(n - 2);

return ans;

}

const n = 4; console.log(numberOfWays(n));

`

Using Top-Down DP (Memoization) - O(n) Time and O(n) Space

If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:

**1. Optimal Substructure: Number of ways to add **i'th tile, i.e., **numberOfWays(i), depends on the optimal solutions of the subproblems **numberOfWays(i-1), and **numberOfWays(i-2). By comparing these optimal substructures, we can efficiently calculate the number of ways to add i' th tile.

**2. Overlapping Subproblems: While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times. For example, for n = 4, **numberOfWays(3) and numberOfWays(2) are called. **numberOfWays(3) again calls numberOfWays(2) which leads to Overlapping Subproblems.

// C++ program to implement // tiling problem using memoization #include <bits/stdc++.h> using namespace std;

int countRecur(int n, vector &memo) {

// Base Case: invalid n 
if (n<0) return 0;

// Base case: valid n 
if (n == 0) return 1;

// If value is memoized
if (memo[n] != -1) return memo[n];

int ans = 0;

// count ways if one tile 
// is placed vertically
ans = countRecur(n-1, memo);

// count ways if two tiles 
// are placed horizontly.
ans += countRecur(n-2, memo);

return memo[n] = ans;

}

int numberOfWays(int n) { vector memo(n+1, -1); return countRecur(n, memo); }

int main() { int n = 4; cout<<numberOfWays(n);

return 0;

}

Java

// Java program to implement // tiling problem using memoization import java.util.Arrays;

class GfG {

static int countRecur(int n, int[] memo) {
    
    // Base Case: invalid n 
    if (n < 0) return 0;
    
    // Base case: valid n 
    if (n == 0) return 1;
    
    // If value is memoized
    if (memo[n] != -1) return memo[n];
    
    int ans = 0;
    
    // count ways if one tile 
    // is placed vertically
    ans = countRecur(n - 1, memo);
    
    // count ways if two tiles 
    // are placed horizontally.
    ans += countRecur(n - 2, memo);
    
    return memo[n] = ans;
}

static int numberOfWays(int n) {
    int[] memo = new int[n + 1];
    Arrays.fill(memo, -1);
    return countRecur(n, memo);
}

public static void main(String[] args) {
    int n = 4;
    System.out.println(numberOfWays(n));
}

}

Python

Python program to implement

tiling problem using memoization

def countRecur(n, memo):

# Base Case: invalid n 
if n < 0:
    return 0

# Base case: valid n 
if n == 0:
    return 1

# If value is memoized
if memo[n] != -1:
    return memo[n]

ans = 0

# count ways if one tile 
# is placed vertically
ans = countRecur(n - 1, memo)

# count ways if two tiles 
# are placed horizontally.
ans += countRecur(n - 2, memo)

memo[n] = ans
return memo[n]

def numberOfWays(n): memo = [-1] * (n + 1) return countRecur(n, memo)

if name == "main": n = 4 print(numberOfWays(n))

C#

// C# program to implement // tiling problem using memoization

using System;

class GfG {

static int countRecur(int n, int[] memo) {
    
    // Base Case: invalid n 
    if (n < 0) return 0;
    
    // Base case: valid n 
    if (n == 0) return 1;
    
    // If value is memoized
    if (memo[n] != -1) return memo[n];
    
    int ans = 0;
    
    // count ways if one tile 
    // is placed vertically
    ans = countRecur(n - 1, memo);
    
    // count ways if two tiles 
    // are placed horizontally.
    ans += countRecur(n - 2, memo);
    
    return memo[n] = ans;
}

static int numberOfWays(int n) {
    int[] memo = new int[n + 1];
    for (int i = 0; i <= n; i++) {
        memo[i] = -1;
    }
    return countRecur(n, memo);
}

static void Main(string[] args) {
    int n = 4;
    Console.WriteLine(numberOfWays(n));
}

}

JavaScript

// JavaScript program to implement // tiling problem using memoization

function countRecur(n, memo) {

// Base Case: invalid n 
if (n < 0) return 0;

// Base case: valid n 
if (n === 0) return 1;

// If value is memoized
if (memo[n] !== -1) return memo[n];

let ans = 0;

// count ways if one tile 
// is placed vertically
ans = countRecur(n - 1, memo);

// count ways if two tiles 
// are placed horizontally.
ans += countRecur(n - 2, memo);

return memo[n] = ans;

}

function numberOfWays(n) { const memo = Array(n + 1).fill(-1); return countRecur(n, memo); }

const n = 4; console.log(numberOfWays(n));

`

Using Bottom-Up DP (Tabulation) - O(n) Time and O(n) Space

The idea is to fill the **DP table based on **previous values. For each tile, we either **add it **vertically or **horizontally to computenumber of ways. The table is filled in an iterative manner from i = 2 to n.

The dynamic programming relation is as follows:

C++ `

// C++ program to implement // tiling problem using tabulation #include <bits/stdc++.h> using namespace std;

int numberOfWays(int n) { if (n==0 || n==1) return 1;

vector<int> dp(n+1);

dp[0] = 1;
dp[1] = 1;

for (int i=2; i<=n; i++) {
    dp[i] = dp[i-1] + dp[i-2];
}

return dp[n];

}

int main() { int n = 4; cout<<numberOfWays(n);

return 0;

}

Java

// Java program to implement // tiling problem using tabulation

import java.util.*;

class GfG {

static int numberOfWays(int n) {
    if (n == 0 || n == 1) return 1;
    
    int[] dp = new int[n + 1];
    
    dp[0] = 1;
    dp[1] = 1;
    
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    
    return dp[n];
}

public static void main(String[] args) {
    int n = 4;
    System.out.println(numberOfWays(n));
}

}

Python

Python program to implement

tiling problem using tabulation

def numberOfWays(n): if n == 0 or n == 1: return 1

dp = [0] * (n + 1)

dp[0] = 1
dp[1] = 1

for i in range(2, n + 1):
    dp[i] = dp[i - 1] + dp[i - 2]

return dp[n]

if name == "main": n = 4 print(numberOfWays(n))

C#

// C# program to implement // tiling problem using tabulation

using System;

class GfG {

static int numberOfWays(int n) {
    if (n == 0 || n == 1) return 1;
    
    int[] dp = new int[n + 1];
    
    dp[0] = 1;
    dp[1] = 1;
    
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    
    return dp[n];
}

static void Main(string[] args) {
    int n = 4;
    Console.WriteLine(numberOfWays(n));
}

}

JavaScript

// JavaScript program to implement // tiling problem using tabulation

function numberOfWays(n) { if (n === 0 || n === 1) return 1;

const dp = new Array(n + 1).fill(0);

dp[0] = 1;
dp[1] = 1;

for (let i = 2; i <= n; i++) {
    dp[i] = dp[i - 1] + dp[i - 2];
}

return dp[n];

}

const n = 4; console.log(numberOfWays(n));

`

Using Space Optimized DP - O(n) Time and O(1) Space

In **previous approach of dynamic programming we have derived the relation between states as given below:

If we observe that for calculating **current dp[i] state we only need **dp[i-1] and **dp[i-2]. There is no need to store all the **previous states just **two previous state is used to compute result.

C++ `

// C++ program to implement // tiling problem using space optimised dp #include <bits/stdc++.h> using namespace std;

int numberOfWays(int n) { if (n==0 || n==1) return 1;

int prev2 = 1;
int prev1 = 1;

for (int i=2; i<=n; i++) {
    int curr = prev1+prev2;
    
    prev2 = prev1;
    prev1 = curr;
}

return prev1;

}

int main() { int n = 4; cout<<numberOfWays(n);

return 0;

}

Java

// Java program to implement // tiling problem using space optimised dp

import java.util.*;

class GfG {

static int numberOfWays(int n) {
    if (n == 0 || n == 1) return 1;
    
    int prev2 = 1;
    int prev1 = 1;
    
    for (int i = 2; i <= n; i++) {
        int curr = prev1 + prev2;
        
        prev2 = prev1;
        prev1 = curr;
    }
    
    return prev1;
}

public static void main(String[] args) {
    int n = 4;
    System.out.println(numberOfWays(n));
}

}

Python

Python program to implement

tiling problem using space optimised dp

def numberOfWays(n): if n == 0 or n == 1: return 1

prev2 = 1
prev1 = 1

for i in range(2, n + 1):
    curr = prev1 + prev2
    prev2 = prev1
    prev1 = curr

return prev1

if name == "main": n = 4 print(numberOfWays(n))

C#

// C# program to implement // tiling problem using space optimised dp

using System;

class GfG {

static int numberOfWays(int n) {
    if (n == 0 || n == 1) return 1;
    
    int prev2 = 1;
    int prev1 = 1;
    
    for (int i = 2; i <= n; i++) {
        int curr = prev1 + prev2;
        
        prev2 = prev1;
        prev1 = curr;
    }
    
    return prev1;
}

static void Main(string[] args) {
    int n = 4;
    Console.WriteLine(numberOfWays(n));
}

}

JavaScript

// JavaScript program to implement // tiling problem using space optimised dp

function numberOfWays(n) { if (n === 0 || n === 1) return 1;

let prev2 = 1;
let prev1 = 1;

for (let i = 2; i <= n; i++) {
    let curr = prev1 + prev2;
    prev2 = prev1;
    prev1 = curr;
}

return prev1;

}

const n = 4; console.log(numberOfWays(n));

`

**Related articles: