Count of Valid Partitions such that all Partitions lie in Range [1, L]
Last Updated :
04 Dec, 2023
Given a string S containing only digits and an integer L, find the number of ways to partition the given string such that each partition forms a number that lies between the range [1, L]. Since the answer may be very large, return the answer modulo 109+7.
Examples:
Input: S = "1000", L = 10000
Output: 1
Explanation: The only possible partition is [1000]
Input: S = "1317", L = 2000
Output: 8
Explanation: Possible partitions are [1317], [131, 7], [13, 17], [1, 317], [13, 1, 7], [1, 31, 7], [1, 3, 17], [1, 3, 1, 7]
Approach: To solve the problem follow the below idea:
The idea is to generate all possible partitions using recursion , if the current partition starts with zero then skip it as no number in the range [1, L] starts with 0, and finally if we found one way of generating different valid partitions from given string then increment the answer by 1. We can further reduce the time complexity using memoization.
Steps to solve the problem:
- Initialize a variable num to keep track of the current partition being formed and ans to keep track of total valid partitions.
- Iterate over the substring starting from the current index i up to the end of the string.
- If the current character at index i is '0', it cannot be a part of any valid partition as no number in range [1, L] starts with 0, so return 0.
- For each digit, update num by appending the digit and check if the number num is less than or equal to the limit L.
- If num is less than or equal to L, make a recursive call to solver with the updated index j+1. This represents the scenario where we continue forming the current number num and move to the next character.
- If num is greater than L, then break the loop.
- If we have reached the end of the string (i == s.size()), return 1. This represents a valid way to split the string.
- Accumulate the results (ans) from all valid recursive calls.
Below is the implementation of the above approach:
C++14
// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
// Function to find the number of ways
// to split the string
int solver(const string& s, long L, int i, vector<int>& dp)
{
// Base case: Reached end of string,
// one valid way to split
if (i == s.size())
return 1;
// Base case: Current character is '0',
// cannot form a valid number
if (s[i] == '0')
return 0;
// Check if result for current index 'i'
// is already computed
if (dp[i] != -1)
return dp[i];
int ans = 0;
long num = 0;
// Iterate over the substring
// starting from current index 'i'
for (int j = i; j < s.size(); j++) {
// Form the current number by
// appending digits
num = num * 10 + s[j] - '0';
// If the formed number exceeds
// the limit 'L', break the loop
if (num > L)
break;
// Recursively call with updated index
// and accumulate results
ans += solver(s, L, j + 1, dp);
ans %= 1000000007;
}
// Memoize the result for current index 'i'
return dp[i] = ans;
}
// Main function to find the number of ways
int NumberOfWays(string s, int L)
{
// Initialize a vector for memoization
vector<int> dp(s.size(), -1);
// Call the solver function
return solver(s, L, 0, dp);
}
int main()
{
string s = "1000";
int L = 10000;
// Call the function and print the result
cout << NumberOfWays(s, L);
return 0;
}
Java
import java.util.Arrays;
public class Main {
// Function to find the number of ways to split the
// string
static int solver(String s, long L, int i, int[] dp)
{
// Base case: Reached the end of the string, one
// valid way to split
if (i == s.length())
return 1;
// Base case: Current character is '0', cannot form
// a valid number
if (s.charAt(i) == '0')
return 0;
// Check if the result for the current index 'i' is
// already computed
if (dp[i] != -1)
return dp[i];
int ans = 0;
long num = 0;
// Iterate over the substring starting from the
// current index 'i'
for (int j = i; j < s.length(); j++) {
// Form the current number by appending digits
num = num * 10 + s.charAt(j) - '0';
// If the formed number exceeds the limit 'L',
// break the loop
if (num > L)
break;
// Recursively call with an updated index and
// accumulate results
ans += solver(s, L, j + 1, dp);
ans %= 1000000007;
}
// Memoize the result for the current index 'i'
dp[i] = ans;
return ans;
}
// Main function to find the number of ways
static int numberOfWays(String s, int L)
{
// Initialize an array for memoization
int[] dp = new int[s.length()];
Arrays.fill(dp, -1);
// Call the solver function
return solver(s, L, 0, dp);
}
public static void main(String[] args)
{
String s = "1000";
int L = 10000;
// Call the function and print the result
System.out.println(numberOfWays(s, L));
}
}
Python3
# Python Implementation
def solver(s, L, i, dp):
# Base case: Reached end of string, one valid way to split
if i == len(s):
return 1
# Base case: Current character is '0', cannot form a valid number
if s[i] == '0':
return 0
# Check if result for current index 'i' is already computed
if dp[i] != -1:
return dp[i]
ans = 0
num = 0
# Iterate over the substring starting from current index 'i'
for j in range(i, len(s)):
# Form the current number by appending digits
num = num * 10 + int(s[j])
# If the formed number exceeds the limit 'L', break the loop
if num > L:
break
# Recursively call with updated index and accumulate results
ans += solver(s, L, j + 1, dp)
ans %= 1000000007
# Memoize the result for current index 'i'
dp[i] = ans
return ans
def NumberOfWays(s, L):
# Initialize a list for memoization
dp = [-1] * len(s)
# Call the solver function
return solver(s, L, 0, dp)
s = "1000"
L = 10000
# Call the function and print the result
print(NumberOfWays(s, L))
# This code is contributed by Sakshi
C#
// C# code for the above approach:
using System;
using System.Collections.Generic;
public class GFG
{
// Function to find the number of
// ways to split the string
static int Solver(string s, long L, int i, int[] dp)
{
// Base case: Reached end of string,
// one valid way to split
if (i == s.Length)
return 1;
// Base case: Current character is '0',
// cannot form a valid number
if (s[i] == '0')
return 0;
// Check if result for current index
// 'i' is already computed
if (dp[i] != -1)
return dp[i];
int ans = 0;
long num = 0;
// Iterate over the substring starting
// from current index 'i'
for (int j = i; j < s.Length; j++)
{
// Form the current number by
// appending digits
num = num * 10 + (s[j] - '0');
// If the formed number exceeds the
// limit 'L', break the loop
if (num > L)
break;
// Recursively call with updated index
// and accumulate results
ans += Solver(s, L, j + 1, dp);
ans %= 1000000007;
}
// Memoize the result for current index 'i'
return dp[i] = ans;
}
// Main function to find the
// number of ways
static int NumberOfWays(string s, int L)
{
// Initialize an array for memoization
int[] dp = new int[s.Length];
Array.Fill(dp, -1);
// Call the Solver function
return Solver(s, L, 0, dp);
}
// Driver code
public static void Main(string[] args)
{
string s = "1000";
int L = 10000;
// Call the function and print the result
Console.WriteLine(NumberOfWays(s, L));
}
}
JavaScript
function solver(s, L, i, dp) {
// Base case: Reached end of string, one valid way to split
if (i === s.length) {
return 1;
}
// Base case: Current character is '0', cannot form a valid number
if (s[i] === '0') {
return 0;
}
// Check if result for current index 'i' is already computed
if (dp[i] !== -1) {
return dp[i];
}
let ans = 0;
let num = 0;
// Iterate over the substring starting from current index 'i'
for (let j = i; j < s.length; j++) {
// Form the current number by appending digits
num = num * 10 + parseInt(s[j]);
// If the formed number exceeds the limit 'L', break the loop
if (num > L) {
break;
}
// Recursively call with updated index and accumulate results
ans += solver(s, L, j + 1, dp);
ans %= 1000000007;
}
// Memoize the result for current index 'i'
dp[i] = ans;
return ans;
}
// Main function to find the number of ways
function NumberOfWays(s, L) {
// Initialize an array for memoization
let dp = new Array(s.length).fill(-1);
// Call the solver function
return solver(s, L, 0, dp);
}
// Main function to test the provided example
function main() {
let s = "1000";
let L = 10000;
// Call the function and print the result
console.log(NumberOfWays(s, L));
}
// Call the main function to execute the code
main();
Time Complexity: O(N2), where N is the length of the input string S.
Auxiliary Space: O(N), which is due to dp[] vector used for memoization.
Similar Reads
Minimum partitions of String such that each part is at most K Given a string S of size N consisting of numerical digits 1-9 and a positive integer K, the task is to minimize the partitions of the string such that each part is at most K. If itâs impossible to partition the string print -1. Examples: Input: S = "3456", K = 45Output: 2Explanation: One possible wa
8 min read
Count ways to partition a string such that both parts have equal distinct characters Content has been removed on Author's request.
1 min read
Count number of ways to partition a set into k subsets Given two numbers n and k where n represents a number of elements in a set, find a number of ways to partition the set into k subsets.Example: Input: n = 3, k = 2Output: 3Explanation: Let the set be [1, 2, 3], we can partition it into 3 subsets in the following ways [[1,2], [3]], [[1], [2,3]], [[1,3
15+ min read
Count numbers present in partitions of N Given an integer N, the task is to count the numbers in ordered integer partitions of N.Examples: Input: N = 3 Output: 8 Integer partitions of N(=3) are {{1 + 1 + 1}, {1 + 2}, {2 + 1}, {3}}. Numbers in integer partition of N are:{1, 1, 1, 1, 2, 2, 1, 3} Therefore, the count of numbers in integer par
3 min read
Partitions possible such that the minimum element divides all the other elements of the partition Given an integer array arr[], the task is to count the number of partitions possible such that in each partition the minimum element divides all the other elements of the partition. The partition need not be continuous.Examples: Input: arr[] = {10, 7, 20, 21, 13} Output: 3 The possible partitions ar
6 min read