Count of different ways to express N as the sum of 1, 3 and 4 (original) (raw)

Given a positive integer **n, the task is to **count the number of ways to express **n as a **sum of 1, 3 and 4.

**Examples:

**Input: n = 4
**Output: 4
**Explanation: There is 4 ways to represent 4 as sum of 1, 3 and 4: (1+1+1+1), (1+3), (3+1) and (4).

**Input: n = 3
**Output: 2
**Explanation: There is 2 ways to represent 3 as sum of 1, 3 and 4: (1+1+1) and (3).

Table of Content

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

The idea is to recursively explore the possibilities of including **1, 3, or 4 in the sum. For any **n, the **result can be computed as the sum of ways for **n-1, n-3 and n-4.

Mathematically the recurrence relation will look like the following:

**countWays(n) = countWays(n-1) + countWays(n-3) + countWays(n-4).

**Base Cases:

C++ `

// C++ Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using recursion #include using namespace std;

int countWays(int n) {

// Base cases
if (n == 0) return 1;
if (n < 0) return 0;

// Recursive cases
return countWays(n - 1) + 
       countWays(n - 3) + 
       countWays(n - 4);

}

int main() { int n = 5; cout << countWays(n); return 0; }

Java

// Java Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using recursion

class GfG {

static int countWays(int n) {

    // Base cases
    if (n == 0) return 1;
    if (n < 0) return 0;

    // Recursive cases
    return countWays(n - 1) + 
           countWays(n - 3) + 
           countWays(n - 4);
}

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

}

Python

Python Program to count the number of ways

to express N as the sum of 1, 3, and 4

using recursion

def countWays(n):

# Base cases
if n == 0:
    return 1
if n < 0:
    return 0

# Recursive cases
return countWays(n - 1) + countWays(n - 3) + countWays(n - 4)

if name == "main": n = 5 print(countWays(n))

C#

// C# Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using recursion

using System;

class GfG {

static int countWays(int n) {

    // Base cases
    if (n == 0) return 1;
    if (n < 0) return 0;

    // Recursive cases
    return countWays(n - 1) + 
           countWays(n - 3) + 
           countWays(n - 4);
}

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

}

JavaScript

// JavaScript Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using recursion

function countWays(n) {

// Base cases
if (n === 0) return 1;
if (n < 0) return 0;

// Recursive cases
return countWays(n - 1) + 
       countWays(n - 3) + 
       countWays(n - 4);

}

let n = 5; console.log(countWays(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 make **sum n, i.e., **countWays(n), depends on the optimal solutions of the subproblems **countWays(n-1), countWays(n-3) and countWays(n-4). By combining these optimal substructures, we can efficiently calculate the number of ways to make sum **n.

**2. Overlapping Subproblems: While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times.

// C++ Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using memoization #include <bits/stdc++.h> using namespace std;

int countRecur(int n, vector &memo) {

// Base cases
if (n == 0) return 1;
if (n < 0) return 0;

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

// Recursive cases
return memo[n] =
    countRecur(n - 1, memo) + 
    countRecur(n - 3, memo) + 
    countRecur(n - 4, memo);

}

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

int main() { int n = 5; cout << countWays(n); return 0; }

Java

// Java Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using memoization

import java.util.Arrays;

class GfG {

static int countRecur(int n, int[] memo) {

    // Base cases
    if (n == 0) return 1;
    if (n < 0) return 0;

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

    // Recursive cases
    return memo[n] = countRecur(n - 1, memo) +
                     countRecur(n - 3, memo) +
                     countRecur(n - 4, memo);
}

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

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

}

Python

Python Program to count the number of ways

to express N as the sum of 1, 3, and 4

using memoization

def countRecur(n, memo):

# Base cases
if n == 0:
    return 1
if n < 0:
    return 0

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

# Recursive cases
memo[n] = countRecur(n - 1, memo) + \
countRecur(n - 3, memo) + countRecur(n - 4, memo)
return memo[n]

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

if name == "main": n = 5 print(countWays(n))

C#

// C# Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using memoization

using System;

class GfG {

static int countRecur(int n, int[] memo) {

    // Base cases
    if (n == 0) return 1;
    if (n < 0) return 0;

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

    // Recursive cases
    return memo[n] = countRecur(n - 1, memo) +
                     countRecur(n - 3, memo) +
                     countRecur(n - 4, memo);
}

static int countWays(int n) {
    int[] memo = new int[n + 1];
    Array.Fill(memo, -1);
    return countRecur(n, memo);
}

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

}

JavaScript

// JavaScript Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using memoization

function countRecur(n, memo) {

// Base cases
if (n === 0) return 1;
if (n < 0) return 0;

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

// Recursive cases
return memo[n] = countRecur(n - 1, memo) +
                 countRecur(n - 3, memo) +
                 countRecur(n - 4, memo);

}

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

const n = 5; console.log(countWays(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 **n, its value is dependent on **n-1, n-3 and n-4. The table is filled in an iterative manner from i = 1 to i = n.

The dynamic programming relation is as follows:

C++ `

// C++ Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using tabulation #include <bits/stdc++.h> using namespace std;

int countWays(int n) { vector dp(n + 1, 0); dp[0] = 1;

for (int i = 1; i <= n; i++) {

    // Calculate dp[i].
    if (i - 1 >= 0)
        dp[i] += dp[i - 1];
    if (i - 3 >= 0)
        dp[i] += dp[i - 3];
    if (i - 4 >= 0)
        dp[i] += dp[i - 4];
}

return dp[n];

}

int main() {

int n = 5;
cout << countWays(n);
return 0;

}

Java

// Java Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using tabulation

class GfG {

static int countWays(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;

    for (int i = 1; i <= n; i++) {

        // Calculate dp[i].
        if (i - 1 >= 0) dp[i] += dp[i - 1];
        if (i - 3 >= 0) dp[i] += dp[i - 3];
        if (i - 4 >= 0) dp[i] += dp[i - 4];
    }

    return dp[n];
}

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

}

Python

Python Program to count the number of ways

to express N as the sum of 1, 3, and 4

using tabulation

def countWays(n): dp = [0] * (n + 1) dp[0] = 1

for i in range(1, n + 1):

    # Calculate dp[i].
    if i - 1 >= 0:
        dp[i] += dp[i - 1]
    if i - 3 >= 0:
        dp[i] += dp[i - 3]
    if i - 4 >= 0:
        dp[i] += dp[i - 4]

return dp[n]

if name == "main": n = 5 print(countWays(n))

C#

// C# Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using tabulation

using System;

class GfG {

static int countWays(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;

    for (int i = 1; i <= n; i++) {

        // Calculate dp[i].
        if (i - 1 >= 0) dp[i] += dp[i - 1];
        if (i - 3 >= 0) dp[i] += dp[i - 3];
        if (i - 4 >= 0) dp[i] += dp[i - 4];
    }

    return dp[n];
}

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

}

JavaScript

// JavaScript Program to count the number of ways // to express N as the sum of 1, 3, and 44 // using tabulation

function countWays(n) { const dp = Array(n + 1).fill(0); dp[0] = 1;

for (let i = 1; i <= n; i++) {

    // Calculate dp[i].
    if (i - 1 >= 0) dp[i] += dp[i - 1];
    if (i - 3 >= 0) dp[i] += dp[i - 3];
    if (i - 4 >= 0) dp[i] += dp[i - 4];
}

return dp[n];

}

const n = 5; console.log(countWays(n));

`

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

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

If we observe that for calculating **current dp[i] state we only need previous **4 states of dp. There is no need to store all the **previous states.

C++ `

// C++ Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using space optimised dp #include <bits/stdc++.h> using namespace std;

int countWays(int n) {

// Return values for 1st 
// 4 states
if (n==1) return 1;
if (n==2) return 1;
if (n==3) return 2;
if (n==4) return 4;

vector<int> dp(4);
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
dp[3] = 4;

for (int i=5; i<=n; i++) {
    
    int curr = dp[0]+dp[1]+dp[3];
    
    // Update values
    dp[0] = dp[1];
    dp[1] = dp[2];
    dp[2] = dp[3];
    dp[3] = curr;
}

return dp[3];

}

int main() { int n = 5; cout << countWays(n); return 0; }

Java

// Java Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using space optimised dp

class GfG {

static int countWays(int n) {
    
    // Return values for 1st 
    // 4 states
    if (n == 1) return 1;
    if (n == 2) return 1;
    if (n == 3) return 2;
    if (n == 4) return 4;
    
    int[] dp = new int[4];
    dp[0] = 1;
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = 4;

    for (int i = 5; i <= n; i++) {

        int curr = dp[0] + dp[1] + dp[3];

        // Update values
        dp[0] = dp[1];
        dp[1] = dp[2];
        dp[2] = dp[3];
        dp[3] = curr;
    }

    return dp[3];
}

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

}

Python

Python Program to count the number of ways

to express N as the sum of 1, 3, and 4

using space optimised dp

def countWays(n):

# Return values for 1st 
# 4 states
if n == 1:
    return 1
if n == 2:
    return 1
if n == 3:
    return 2
if n == 4:
    return 4

dp = [1, 1, 2, 4]

for i in range(5, n + 1):

    curr = dp[0] + dp[1] + dp[3]

    # Update values
    dp[0] = dp[1]
    dp[1] = dp[2]
    dp[2] = dp[3]
    dp[3] = curr

return dp[3]

if name == "main": n = 5 print(countWays(n))

C#

// C# Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using space optimised dp

using System;

class GfG {

static int countWays(int n) {
    
    // Return values for 1st 
    // 4 states
    if (n == 1) return 1;
    if (n == 2) return 1;
    if (n == 3) return 2;
    if (n == 4) return 4;

    int[] dp = new int[4];
    dp[0] = 1;
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = 4;

    for (int i = 5; i <= n; i++) {

        int curr = dp[0] + dp[1] + dp[3];

        // Update values
        dp[0] = dp[1];
        dp[1] = dp[2];
        dp[2] = dp[3];
        dp[3] = curr;
    }

    return dp[3];
}

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

}

JavaScript

// JavaScript Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using space optimised dp

function countWays(n) {

// Return values for 1st 
// 4 states
if (n === 1) return 1;
if (n === 2) return 1;
if (n === 3) return 2;
if (n === 4) return 4;

const dp = [1, 1, 2, 4];

for (let i = 5; i <= n; i++) {

    const curr = dp[0] + dp[1] + dp[3];

    // Update values
    dp[0] = dp[1];
    dp[1] = dp[2];
    dp[2] = dp[3];
    dp[3] = curr;
}

return dp[3];

}

const n = 5; console.log(countWays(n));

`