Count of different ways to express N as the sum of 1, 3 and 4
Last Updated : 03 Dec, 2024
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).
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:
- countWays(n) = 0, if n < 0.
- countWays(n) = 1, if n == 0.
C++ // C++ Program to count the number of ways // to express N as the sum of 1, 3, and 4 // using recursion #include <iostream> 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.
- There is only one parameter: n that changes in the recursive solution. So we create a 1D array of size n for memoization.
- We initialize this array as -1 to indicate nothing is computed initially.
- Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same subproblems.
C++ // 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<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); } int countWays(int n) { vector<int> 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:
- dp[i] = sum(dp[i-j]) for value of j = {1, 3, 4} and i-j >=0.
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<int> 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:
- dp[i] = sum(dp[i-j]) for value of j = {1, 3, 4} and i – j >=0.
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));
Similar Reads
Binary Exponentiation for Competitive Programming
In competitive programming, we often need to do a lot of big number calculations fast. Binary exponentiation is like a super shortcut for doing powers and can make programs faster. This article will show you how to use this powerful trick to enhance your coding skills. Table of ContentWhat is Binary
15+ min read
Padovan Sequence
Padovan Sequence similar to Fibonacci sequence with similar recursive structure. The recursive formula is, P(n) = P(n-2) + P(n-3) P(0) = P(1) = P(2) = 1 Fibonacci Sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...... Spiral of squares with side lengths which follow the Fibonacci sequence. Padovan Sequ
4 min read
Count of different ways to express N as the sum of 1, 3 and 4
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 = 4Output: 4Explanation: 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 = 3Output: 2Explanation: There is 2 ways to represent 3
13 min read
Find the Nth element of the modified Fibonacci series
Given two integers A and B which are the first two terms of the series and another integer N. The task is to find the Nth number using Fibonacci rule i.e. fib(i) = fib(i - 1) + fib(i - 2)Example: Input: A = 2, B = 3, N = 4 Output: 8 The series will be 2, 3, 5, 8, 13, 21, ... And the 4th element is 8
5 min read
Program to Check Geometric Progression
A sequence of numbers is called a Geometric progression if the ratio of any two consecutive terms is always the same. In simple terms, A geometric series is a list of numbers where each number, or term, is found by multiplying the previous term by a common ratio r. The general form of Geometric Prog
6 min read
Carol Number
A Carol number is an integer of the form 4n - 2(n+1) - 1. An equivalent formula is (2n-1)2 - 2.An Interesting Property : For n > 2, the binary representation of the n-th Carol number is n-2 consecutive one's, a single zero in the middle, and n + 1 more consecutive one's. Example, n = 4 carol numb
3 min read
Matrix Exponentiation
Matrix Exponentiation is a technique used to calculate a matrix raised to a power efficiently, that is in logN time. It is mostly used for solving problems related to linear recurrences. Idea behind Matrix Exponentiation:Similar to Binary Exponentiation which is used to calculate a number raised to
15+ min read
String hashing using Polynomial rolling hash function
Given a string str of length n, your task is to find its hash value using polynomial rolling hash function. Note: If two strings are equal, their hash values should also be equal. But the inverse need not be true. Examples: Input: str = "geeksforgeeks"Output: 609871790 Input: str = "polynomial"Outpu
15+ min read
Compute nCr%p using Fermat Little Theorem
Given three numbers n, r and p, compute the value of nCr mod p. Here p is a prime number greater than n. Here nCr is Binomial Coefficient.Example: Input: n = 10, r = 2, p = 13 Output: 6 Explanation: 10C2 is 45 and 45 % 13 is 6. Input: n = 6, r = 2, p = 13 Output: 2Recommended PracticenCrTry It! We h
15+ min read
Generalized Fibonacci Numbers
We all know that Fibonacci numbers (Fn) are defined by the recurrence relation Fibonacci Numbers (Fn) = F(n-1) + F(n-2) with seed values F0 = 0 and F1 = 1 Similarly, we can generalize these numbers. Such a number sequence is known as Generalized Fibonacci number (G). Generalized Fibonacci number (G)
10 min read