Different ways to sum n using numbers greater than or equal to m
Last Updated : 02 Dec, 2024
Given two natural numbers n and m. The task is to find the number of ways in which the numbers that are greater than or equal to m can be added to get the sum n.
Examples:
Input: n = 3, m = 1
Output: 3
Explanation: Three different ways to get sum n such that each term is greater than or equal to m are 1 + 1 + 1, 1 + 2 and 3
Input: n = 2, m = 1
Output: 2
Explanation: Two different ways to get sum n such that each term is greater than or equal to m are 1 + 1 and 2
Using Recursion - O(2^n) Time and O(n) Space
The idea is to find the number of ways to reach n by trying each value of m from m to n. Starting from the target sum n, for each m, we can either include it or exclude it. If we include it, we subtract its value from sum and recursively try to make the remaining amount with the same value. If we exclude it, we move to (m+1).
Mathematically the recurrence relation will look like the following:
- count(m, n) = count(m, n-m) + count(m+1, n)
Base cases:
- count(m, n) = 0, if n < 0 or m > n.
- count(m, n) = 1, if n == 0.
C++ // C++ program to find ways // to make sum n, using values // greater than equal to m using recursion #include <bits/stdc++.h> using namespace std; int countRecur(int m, int n) { // base case if (n==0) return 1; if (m>n || n<0) return 0; // include current m int take = countRecur(m, n-m); // skip current m int noTake = countRecur(m+1, n); return take+noTake; } int count(int m, int n) { return countRecur(m, n); } int main() { int n = 3, m = 1; cout<<count(m,n); return 0; }
Java // Java program to find ways // to make sum n, using values // greater than equal to m using recursion class GfG { // Function to recursively count ways static int countRecur(int m, int n) { // base case if (n == 0) return 1; if (m > n || n < 0) return 0; // include current m int take = countRecur(m, n - m); // skip current m int noTake = countRecur(m + 1, n); return take + noTake; } static int count(int m, int n) { return countRecur(m, n); } public static void main(String[] args) { int n = 3, m = 1; System.out.println(count(m, n)); } }
Python # Python program to find ways # to make sum n, using values # greater than equal to m using recursion def countRecur(m, n): # base case if n == 0: return 1 if m > n or n < 0: return 0 # include current m take = countRecur(m, n - m) # skip current m noTake = countRecur(m + 1, n) return take + noTake def count(m, n): return countRecur(m, n) if __name__ == "__main__": n = 3 m = 1 print(count(m, n))
C# // C# program to find ways // to make sum n, using values // greater than equal to m using recursion using System; class GfG { // Function to recursively count ways static int countRecur(int m, int n) { // base case if (n == 0) return 1; if (m > n || n < 0) return 0; // include current m int take = countRecur(m, n - m); // skip current m int noTake = countRecur(m + 1, n); return take + noTake; } static int count(int m, int n) { return countRecur(m, n); } static void Main(string[] args) { int n = 3, m = 1; Console.WriteLine(count(m, n)); } }
JavaScript // JavaScript program to find ways // to make sum n, using values // greater than equal to m using recursion // Function to recursively count ways function countRecur(m, n) { // base case if (n === 0) return 1; if (m > n || n < 0) return 0; // include current m const take = countRecur(m, n - m); // skip current m const noTake = countRecur(m + 1, n); return take + noTake; } function count(m, n) { return countRecur(m, n); } const n = 3, m = 1; console.log(count(m, n));
Using Top-Down DP (Memoization) - O(n^2) Time and O(n^2) 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 at value m, i.e., count(m, n), depends on the optimal solutions of the subproblems count(m, n-m) and count(m+1, n). By combining these optimal substructures, we can efficiently calculate the number of ways to make target sum n at value m.
2. Overlapping Subproblems: While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times.
- There are only are two parameters: m and n that changes in the recursive solution. The value of m will be in range [m, n] So we create a 2D matrix of size (n+1)*(n+1) for memoization.
- We initialize this matrix 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 find ways // to make sum n, using values // greater than equal to m using memoization #include <bits/stdc++.h> using namespace std; int countRecur(int m, int n, vector<vector<int>> &memo) { // base case if (n==0) return 1; if (m>n || n<0) return 0; // If value if memoized if (memo[m][n]!=-1) return memo[m][n]; // include current m int take = countRecur(m, n-m, memo); // skip current m int noTake = countRecur(m+1, n, memo); return memo[m][n] = take+noTake; } int count(int m, int n) { vector<vector<int>> memo(n+1, vector<int>(n+1, -1)); return countRecur(m, n, memo); } int main() { int n = 3, m = 1; cout<<count(m,n); return 0; }
Java // Java program to find ways // to make sum n, using values // greater than equal to m using memoization class GfG { // Function to recursively count ways static int countRecur(int m, int n, int[][] memo) { // base case if (n == 0) return 1; if (m > n || n < 0) return 0; // If value is memoized if (memo[m][n] != -1) return memo[m][n]; // include current m int take = countRecur(m, n - m, memo); // skip current m int noTake = countRecur(m + 1, n, memo); return memo[m][n] = take + noTake; } static int count(int m, int n) { int[][] memo = new int[n + 1][n + 1]; for (int[] row : memo) { java.util.Arrays.fill(row, -1); } return countRecur(m, n, memo); } public static void main(String[] args) { int n = 3, m = 1; System.out.println(count(m, n)); } }
Python # Python program to find ways # to make sum n, using values # greater than equal to m using memoization def countRecur(m, n, memo): # base case if n == 0: return 1 if m > n or n < 0: return 0 # If value is memoized if memo[m][n] != -1: return memo[m][n] # include current m take = countRecur(m, n - m, memo) # skip current m noTake = countRecur(m + 1, n, memo) memo[m][n] = take + noTake return memo[m][n] def count(m, n): memo = [[-1 for _ in range(n + 1)] for _ in range(n + 1)] return countRecur(m, n, memo) if __name__ == "__main__": n = 3 m = 1 print(count(m, n))
C# // C# program to find ways // to make sum n, using values // greater than equal to m using memoization using System; class GfG { // Function to recursively count ways static int countRecur(int m, int n, int[,] memo) { // base case if (n == 0) return 1; if (m > n || n < 0) return 0; // If value is memoized if (memo[m, n] != -1) return memo[m, n]; // include current m int take = countRecur(m, n - m, memo); // skip current m int noTake = countRecur(m + 1, n, memo); return memo[m, n] = take + noTake; } static int count(int m, int n) { int[,] memo = new int[n + 1, n + 1]; for (int i = 0; i <= n; i++) { for (int j = 0; j <= n; j++) { memo[i, j] = -1; } } return countRecur(m, n, memo); } static void Main(string[] args) { int n = 3, m = 1; Console.WriteLine(count(m, n)); } }
JavaScript // JavaScript program to find ways // to make sum n, using values // greater than equal to m using memoization // Function to recursively count ways function countRecur(m, n, memo) { // base case if (n === 0) return 1; if (m > n || n < 0) return 0; // If value is memoized if (memo[m][n] !== -1) return memo[m][n]; // include current m const take = countRecur(m, n - m, memo); // skip current m const noTake = countRecur(m + 1, n, memo); memo[m][n] = take + noTake; return memo[m][n]; } function count(m, n) { const memo = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1)); return countRecur(m, n, memo); } const n = 3, m = 1; console.log(count(m, n));
Using Bottom-Up DP (Tabulation) - O(n^2) Time and O(n^2) Space
The idea is to fill the DP table based on previous values. For each value m, we either include it or exclude it to compute the number of ways needed for each sum n. The table is filled in an iterative manner from i = n to i = m and for each sum from 1 to n.
The dynamic programming relation is as follows:
- if (sum-i) is greater than equal to 0, then dp[i][sum] = dp[i][sum-i] + dp[i+1][sum]
- else dp[i][sum] = dp[i+1][sum].
C++ // C++ program to find ways // to make sum n, using values // greater than equal to m using tabulation #include <bits/stdc++.h> using namespace std; int count(int m, int n) { if (m>n) return 0; vector<vector<int>> dp(n+2, vector<int>(n+1)); // set dp[i][0] = 1 for (int i=0; i<n+2; i++) { dp[i][0] = 1; } for (int i=n; i>=m; i--) { for (int sum=1; sum<=n; sum++) { if (sum-i>=0) { dp[i][sum] = dp[i][sum-i] + dp[i+1][sum]; } else { dp[i][sum] = dp[i+1][sum]; } } } return dp[m][n]; } int main() { int n = 3, m = 1; cout<<count(m,n); return 0; }
Java // Java program to find ways // to make sum n, using values // greater than equal to m using tabulation class GfG { static int count(int m, int n) { if (m > n) return 0; int[][] dp = new int[n + 2][n + 1]; // set dp[i][0] = 1 for (int i = 0; i < n + 2; i++) { dp[i][0] = 1; } for (int i = n; i >= m; i--) { for (int sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[i][sum] = dp[i][sum - i] + dp[i + 1][sum]; } else { dp[i][sum] = dp[i + 1][sum]; } } } return dp[m][n]; } public static void main(String[] args) { int n = 3, m = 1; System.out.println(count(m, n)); } }
Python # Python program to find ways # to make sum n, using values # greater than equal to m using tabulation def count(m, n): if m > n: return 0 dp = [[0] * (n + 1) for _ in range(n + 2)] # set dp[i][0] = 1 for i in range(n + 2): dp[i][0] = 1 for i in range(n, m - 1, -1): for sum in range(1, n + 1): if sum - i >= 0: dp[i][sum] = dp[i][sum - i] + dp[i + 1][sum] else: dp[i][sum] = dp[i + 1][sum] return dp[m][n] if __name__ == "__main__": n = 3 m = 1 print(count(m, n))
C# // C# program to find ways // to make sum n, using values // greater than equal to m using tabulation using System; class GfG { static int count(int m, int n) { if (m > n) return 0; int[,] dp = new int[n + 2, n + 1]; // set dp[i, 0] = 1 for (int i = 0; i < n + 2; i++) { dp[i, 0] = 1; } for (int i = n; i >= m; i--) { for (int sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[i, sum] = dp[i, sum - i] + dp[i + 1, sum]; } else { dp[i, sum] = dp[i + 1, sum]; } } } return dp[m, n]; } static void Main(string[] args) { int n = 3, m = 1; Console.WriteLine(count(m, n)); } }
JavaScript // JavaScript program to find ways // to make sum n, using values // greater than equal to m using tabulation function count(m, n) { if (m > n) return 0; const dp = Array.from({ length: n + 2 }, () => Array(n + 1).fill(0)); // set dp[i][0] = 1 for (let i = 0; i < n + 2; i++) { dp[i][0] = 1; } for (let i = n; i >= m; i--) { for (let sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[i][sum] = dp[i][sum - i] + dp[i + 1][sum]; } else { dp[i][sum] = dp[i + 1][sum]; } } } return dp[m][n]; } const n = 3, m = 1; console.log(count(m, n));
Using Space Optimized DP - O(n^2) Time and O(n) Space
In previous approach of dynamic programming we have derive the relation between states as given below:
- if (sum-i) is greater than 0, then dp[i][sum] = dp[i][sum-i] + dp[i+1][sum]
- else dp[i][sum] = dp[i+1][sum].
If we observe that for calculating current dp[i][sum] state we only need previous row dp[i-1][sum] or current row dp[i][sum-i]. There is no need to store all the previous states just one previous state is used to compute result.
C++ // C++ program to find ways // to make sum n, using values // greater than equal to m using Space Optimized DP #include <bits/stdc++.h> using namespace std; int count(int m, int n) { if (m > n) return 0; vector<int> dp(n + 1, 0); // set dp[0] = 1 dp[0] = 1; for (int i = n; i >= m; i--) { for (int sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[sum] = dp[sum - i] + dp[sum]; } else { dp[sum] = dp[sum]; } } } return dp[n]; } int main() { int n = 3, m = 1; cout << count(m, n); return 0; }
Java // Java program to find ways // to make sum n, using values // greater than equal to m using Space Optimized DP class GfG { static int count(int m, int n) { if (m > n) return 0; int[] dp = new int[n + 1]; // set dp[0] = 1 dp[0] = 1; for (int i = n; i >= m; i--) { for (int sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[sum] = dp[sum - i] + dp[sum]; } else { dp[sum] = dp[sum]; } } } return dp[n]; } public static void main(String[] args) { int n = 3, m = 1; System.out.println(count(m, n)); } }
Python # Python program to find ways # to make sum n, using values # greater than equal to m using Space Optimized DP def count(m, n): if m > n: return 0 dp = [0] * (n + 1) # set dp[0] = 1 dp[0] = 1 for i in range(n, m - 1, -1): for sum in range(1, n + 1): if sum - i >= 0: dp[sum] = dp[sum - i] + dp[sum] else: dp[sum] = dp[sum] return dp[n] if __name__ == "__main__": n = 3 m = 1 print(count(m, n))
C# // C# program to find ways // to make sum n, using values // greater than equal to m using Space Optimized DP using System; class GfG { static int count(int m, int n) { if (m > n) return 0; int[] dp = new int[n + 1]; // set dp[0] = 1 dp[0] = 1; for (int i = n; i >= m; i--) { for (int sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[sum] = dp[sum - i] + dp[sum]; } else { dp[sum] = dp[sum]; } } } return dp[n]; } static void Main(string[] args) { int n = 3, m = 1; Console.WriteLine(count(m, n)); } }
JavaScript // JavaScript program to find ways // to make sum n, using values // greater than equal to m using Space Optimized DP function count(m, n) { if (m > n) return 0; const dp = new Array(n + 1).fill(0); // set dp[0] = 1 dp[0] = 1; for (let i = n; i >= m; i--) { for (let sum = 1; sum <= n; sum++) { if (sum - i >= 0) { dp[sum] = dp[sum - i] + dp[sum]; } else { dp[sum] = dp[sum]; } } } return dp[n]; } const n = 3, m = 1; console.log(count(m, n));
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem
My Profile