Given a 2 × n board and tiles of size 2 × 1, find the total number of ways to completely fill the board using these tiles. Each tile can be placed either horizontally i.e., as a 1 x 2 tile or vertically i.e., as 2 x 1 tile. Two tiling arrangements are considered different if the placement of at least one tile differs.
Examples:
Input: n = 4
Output: 5 Explanation: For a 2 x 4 board, there are 5 ways.
Input: n = 3
Output: 3 Explanation: For or a 2 x 3 board, there are 3 ways.
[Naive Approach] Using Recursion - O(2^n) Time and O(n) Space
The idea is to use Recursion and breaking the larger problem (size n) into smaller subproblems (sizes n-1 and n-2).
At any point, we have two choices:
Place one vertical tile (2 × 1): This tile will cover one column of the board, leaving a smaller board of size 2 × (n - 1) to be filled.
Place two horizontal tiles (1 × 2): These two tiles will cover two columns together, leaving a smaller board of size 2 × (n - 2) to be filled.
So, to find the total number of ways to fill a 2 × n board, we just need to sum the number of ways to fill the smaller boards obtained by these two choices.
C++
//Driver Code Starts#include<iostream>#include<vector>usingnamespacestd;//Driver Code EndsintnumberOfWays(intn){// Base Caseif(n<0)return0;if(n==0)return1;intans=0;// if one tile is placed verticallyans=numberOfWays(n-1);// if two tiles are placed horizontly.ans+=numberOfWays(n-2);returnans;}//Driver Code Startsintmain(){intn=4;cout<<numberOfWays(n);return0;}//Driver Code Ends
Java
//Driver Code StartsclassGFG{//Driver Code EndsstaticintnumberOfWays(intn){// Base Caseif(n<0)return0;if(n==0)return1;intans=0;// if one tile is placed verticallyans=numberOfWays(n-1);// if two tiles are placed horizontally.ans+=numberOfWays(n-2);returnans;}//Driver Code Startspublicstaticvoidmain(String[]args){intn=4;System.out.println(numberOfWays(n));}}//Driver Code Ends
Python
defnumberOfWays(n):# Base Caseifn<0:return0ifn==0:return1ans=0# if one tile is placed verticallyans=numberOfWays(n-1)# if two tiles are placed horizontally.ans+=numberOfWays(n-2)returnans#Driver Code Startsif__name__=="__main__":n=4print(numberOfWays(n))#Driver Code Ends
C#
//Driver Code StartsusingSystem;classGFG{//Driver Code EndsstaticintnumberOfWays(intn){// Base Caseif(n<0)return0;if(n==0)return1;intans=0;// if one tile is placed verticallyans=numberOfWays(n-1);// if two tiles are placed horizontally.ans+=numberOfWays(n-2);returnans;}//Driver Code StartsstaticvoidMain(){intn=4;Console.WriteLine(numberOfWays(n));}}//Driver Code Ends
JavaScript
functionnumberOfWays(n){// Base Caseif(n<0)return0;if(n===0)return1;letans=0;// if one tile is placed verticallyans=numberOfWays(n-1);// if two tiles are placed horizontally.ans+=numberOfWays(n-2);returnans;}//Driver Code//Driver Code Startsletn=4;console.log(numberOfWays(n));//Driver Code Ends
Output
5
[Better Approach 1] Using Top-Down DP (Memoization) - O(n) Time and O(n) Space
In the recursive approach, we saw that many subproblems are solved repeatedly, leading to redundant computations.
To handle this, we use Dynamic Programming with Memoization. We create a 1D array dp[] of size n + 1, where each element dp[i] represents the number of ways to completely fill a 2 × i board. Since there is only one changing parameter (i) in our recursive function, a 1D array is sufficient. Before solving a subproblem, we first check if it has already been computed.
If yes, we return the stored value from the dp array.
If not, we compute it recursively and store the result in dp[i] for future use.
C++
//Driver Code Starts#include<iostream>#include<vector>usingnamespacestd;//Driver Code EndsintcountRecur(intn,vector<int>&dp){// Base Caseif(n<0)return0;if(n==0)return1;// If value is memoizedif(dp[n]!=-1)returndp[n];intans=0;// if one tile is placed verticallyans=countRecur(n-1,dp);//if two tiles are placed horizontly.ans+=countRecur(n-2,dp);returndp[n]=ans;}intnumberOfWays(intn){vector<int>dp(n+1,-1);returncountRecur(n,dp);}//Driver Code Startsintmain(){intn=4;cout<<numberOfWays(n);return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.Arrays;classGFG{//Driver Code EndsstaticintcountRecur(intn,int[]dp){// Base Caseif(n<0)return0;if(n==0)return1;// If value is memoizedif(dp[n]!=-1)returndp[n];intans=0;// if one tile is placed verticallyans=countRecur(n-1,dp);//if two tiles are placed horizontly.ans+=countRecur(n-2,dp);returndp[n]=ans;}staticintnumberOfWays(intn){int[]dp=newint[n+1];Arrays.fill(dp,-1);returncountRecur(n,dp);}//Driver Code Startspublicstaticvoidmain(String[]args){intn=4;System.out.println(numberOfWays(n));}}//Driver Code Ends
Python
defcountRecur(n,dp):# Base Caseifn<0:return0ifn==0:return1# If value is memoizedifdp[n]!=-1:returndp[n]ans=0# if one tile is placed verticallyans=countRecur(n-1,dp)# if two tiles are placed horizontly.ans+=countRecur(n-2,dp)dp[n]=ansreturndp[n]defnumberOfWays(n):dp=[-1]*(n+1)returncountRecur(n,dp)if__name__=="__main__":#Driver Code Startsn=4print(numberOfWays(n))#Driver Code Ends
C#
//Driver Code StartsusingSystem;classGFG{//Driver Code EndsstaticintcountRecur(intn,int[]dp){// Base Caseif(n<0)return0;if(n==0)return1;// If value is memoizedif(dp[n]!=-1)returndp[n];intans=0;// if one tile is placed verticallyans=countRecur(n-1,dp);//if two tiles are placed horizontly.ans+=countRecur(n-2,dp);returndp[n]=ans;}staticintnumberOfWays(intn){int[]dp=newint[n+1];for(inti=0;i<=n;i++)dp[i]=-1;returncountRecur(n,dp);}//Driver Code StartsstaticvoidMain(){intn=4;Console.WriteLine(numberOfWays(n));}}//Driver Code Ends
JavaScript
functioncountRecur(n,dp){// Base Caseif(n<0)return0;if(n===0)return1;// If value is memoizedif(dp[n]!==-1)returndp[n];letans=0;// if one tile is placed verticallyans=countRecur(n-1,dp);//if two tiles are placed horizontly.ans+=countRecur(n-2,dp);returndp[n]=ans;}functionnumberOfWays(n){constdp=newArray(n+1).fill(-1);returncountRecur(n,dp);}//Driver Code//Driver Code Startsletn=4;console.log(numberOfWays(n));//Driver Code Ends
Output
5
[Better Approach 2] Using Bottom-Up DP (Tabulation) - O(n) Time and O(n) Space
In this approach, instead of using recursion, we build the solution iteratively from bottom to top.
We create a 1D DP array dp[n+1] to store the results of already computed subproblems, since there is only one parameter — n — that changes in the recursive solution. First, we will solve some smaller problems for which we define the base cases:
dp[0] = 1 — There is one way to fill a 2×0 board.
dp[1] = 1 — There is only one way to fill a 2×1 board.
We start from these base cases, and then we have two choices:
Place one vertical tile, leaving a 2×(i−1) board - dp[i−1]
Place two horizontal tiles, leaving a 2×(i−2) board - dp[i−2]
After filling the DP table iteratively, dp[n] will give the total number of ways to completely fill the 2×n board
C++
//Driver Code Starts#include<iostream>#include<vector>usingnamespacestd;//Driver Code EndsintnumberOfWays(intn){if(n==0||n==1)return1;// Create a 1D DP array to store results of subproblemsvector<int>dp(n+1);// Initialize base casesdp[0]=1;dp[1]=1;// Build the solution iteratively (Bottom-Up DP)for(inti=2;i<=n;i++){// Two choices:dp[i]=dp[i-1]+dp[i-2];}returndp[n];}//Driver Code Startsintmain(){intn=4;cout<<numberOfWays(n);return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.Arrays;publicclassGFG{//Driver Code EndsstaticintnumberOfWays(intn){if(n==0||n==1)return1;// Create a 1D DP array to store results of subproblemsint[]dp=newint[n+1];// Initialize base casesdp[0]=1;dp[1]=1;// Build the solution iteratively (Bottom-Up DP)for(inti=2;i<=n;i++){// Two choices:dp[i]=dp[i-1]+dp[i-2];}returndp[n];}//Driver Code Startspublicstaticvoidmain(String[]args){intn=4;System.out.println(numberOfWays(n));}}//Driver Code Ends
Python
defnumberOfWays(n):ifn==0orn==1:return1# Create a 1D DP array to store results of subproblemsdp=[0]*(n+1)# Initialize base casesdp[0]=1dp[1]=1# Build the solution iteratively (Bottom-Up DP)foriinrange(2,n+1):# Two choices:dp[i]=dp[i-1]+dp[i-2]returndp[n]if__name__=="__main__":#Driver Code Startsn=4print(numberOfWays(n))#Driver Code Ends
C#
//Driver Code StartsusingSystem;classGFG{//Driver Code EndsstaticintnumberOfWays(intn){if(n==0||n==1)return1;// Create a 1D DP array to store results of subproblemsint[]dp=newint[n+1];// Initialize base casesdp[0]=1;dp[1]=1;// Build the solution iteratively (Bottom-Up DP)for(inti=2;i<=n;i++){// Two choices:dp[i]=dp[i-1]+dp[i-2];}returndp[n];}//Driver Code StartsstaticvoidMain(){intn=4;Console.WriteLine(numberOfWays(n));}}//Driver Code Ends
JavaScript
functionnumberOfWays(n){if(n===0||n===1)return1;// Create a 1D DP array to store results of subproblemsletdp=newArray(n+1);// Initialize base casesdp[0]=1;dp[1]=1;// Build the solution iteratively (Bottom-Up DP)for(leti=2;i<=n;i++){// Two choices:dp[i]=dp[i-1]+dp[i-2];}returndp[n];}//Driver Code//Driver Code Startsletn=4;console.log(numberOfWays(n));//Driver Code Ends
Output
5
[Expected Approach] Using Space Optimized DP - O(n) Time and O(1) Space
In the previous dynamic programming approach, we used a 1D array dp[] to store all computed results up to n. However, if we observe carefully, to calculate the current state dp[i], we only need the last two states — dp[i-1] and dp[i-2]. This means we don’t need to maintain the entire DP array; instead, we can optimize the space by storing only these two values.
We can use two variables, say prev1 and prev2, where:
prev1 represents the number of ways for dp[i-1]
prev2 represents the number of ways for dp[i-2]
This way, we iteratively move forward while using only constant space instead of an entire array.
C++
//Driver Code Starts#include<iostream>#include<vector>usingnamespacestd;//Driver Code EndsintnumberOfWays(intn){// Base casesif(n==0||n==1)return1;intprev2=1;intprev1=1;// Iterate from 2 to n to build the result for(inti=2;i<=n;i++){// Current state depends on the sum of previous two statesintcurr=prev1+prev2;// Move the variables one step aheadprev2=prev1;prev1=curr;}returnprev1;}//Driver Code Startsintmain(){intn=4;cout<<numberOfWays(n);return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.Arrays;classGFG{//Driver Code EndsstaticintnumberOfWays(intn){// Base casesif(n==0||n==1)return1;intprev2=1;intprev1=1;// Iterate from 2 to n to build the result for(inti=2;i<=n;i++){// Current state depends on the sum of previous two statesintcurr=prev1+prev2;// Move the variables one step aheadprev2=prev1;prev1=curr;}returnprev1;}//Driver Code Startspublicstaticvoidmain(String[]args){intn=4;System.out.println(numberOfWays(n));}}//Driver Code Ends
Python
defnumberOfWays(n):# Base casesifn==0orn==1:return1prev2=1prev1=1# Iterate from 2 to n to build the result foriinrange(2,n+1):# Current state depends on the sum of previous two statescurr=prev1+prev2# Move the variables one step aheadprev2=prev1prev1=currreturnprev1#Driver Code Startsif__name__=="__main__":n=4print(numberOfWays(n))#Driver Code Ends
C#
//Driver Code StartsusingSystem;classGFG{//Driver Code EndsstaticintnumberOfWays(intn){// Base casesif(n==0||n==1)return1;intprev2=1;intprev1=1;// Iterate from 2 to n to build the result for(inti=2;i<=n;i++){// Current state depends on the sum of previous two statesintcurr=prev1+prev2;// Move the variables one step aheadprev2=prev1;prev1=curr;}returnprev1;}//Driver Code StartspublicstaticvoidMain(){intn=4;Console.WriteLine(numberOfWays(n));}}//Driver Code Ends
JavaScript
functionnumberOfWays(n){// Base casesif(n===0||n===1)return1;letprev2=1;letprev1=1;// Iterate from 2 to n to build the result for(leti=2;i<=n;i++){// Current state depends on the sum of previous two statesletcurr=prev1+prev2;// Move the variables one step aheadprev2=prev1;prev1=curr;}returnprev1;}// Driver code//Driver Code Startsletn=4;console.log(numberOfWays(n));//Driver Code Ends