Count digit groupings of a number with given constraints

We are given a string consisting of digits, we may group these digits into sub-groups (but maintaining their original order). The task is to count number of groupings such that for every sub-group except the last one, sum of digits in a sub-group is less than or equal to sum of the digits in the sub-group immediately on its right.

For example, a valid grouping of digits of number 1119 is (1-11-9). Sum of digits in first subgroup is 1, next subgroup is 2, and last subgroup is 9. Sum of every subgroup is less than or equal to its immediate right.

Examples :

Input : "1119"
Output: 7
Sub-groups: [1-119], [1-1-19], [1-11-9], [1-1-1-9],
            [11-19] and [111-9].
Note : Here we have included [1119] in the group and
       sum of digits is 12 and this group has no 
       immediate right.

Input : "1234"
Output: 6
Sub-groups : [1234], [1-234], [12-34], [1-2-3-4],
             [12-3-4] and [1-2-34]

Let “length” be the length of input number. A recursive solution is to consider every position from 0 length-1. For every position, recursively count all possible subgroups after it. Below is C++ implementation of naive recursive solution.



C++

// C++ program to count number of 
// ways to group digits of a number 
// such that sum of digits in every 
// subgroup is less than or equal to
// its immediate right subgroup.
#include<bits/stdc++.h>
using namespace std;

// Function to find the subgroups
int countGroups(int position, 
                int previous_sum, 
                int length, char *num)
{
    // Terminating Condition
    if (position == length)
        return 1;

    int res = 0;
    
    // sum of digits
    int sum = 0; 

    // Traverse all digits from
    // current position to rest
    // of the length of string
    for (int i = position; i < length; i++)
    {
        sum += (num[i] - '0');

        // If forward_sum is greater
        // than the previous sum,
        // then call the method again
        if (sum >= previous_sum)

        // Note : We pass current 
        // sum as previous sum
        res += countGroups(i + 1, sum, 
                           length, num);
    }

    // Total number of subgroups
    // till current position
    return res;
}

// Driver Code
int main()
{
    char num[] = "1119";
    int len = strlen(num);
    cout << countGroups(0, 0, len, num);
    return 0;
}

Java

// Java program to count number 
// of ways to group digits of  
// a number such that sum of  
// digits in every subgroup is 
// less than or equal to its 
// immediate right subgroup.
import java.io.*;

class GFG 
{

// Function to find
// the subgroups
static int countGroups(int position, 
                       int previous_sum, 
                       int length, 
                       String num)
{
    // Terminating Condition
    if (position == length)
        return 1;

    int res = 0;
    
    // sum of digits
    int sum = 0; 

    // Traverse all digits from
    // current position to rest
    // of the length of string
    for (int i = position; i < length; i++)
    {
        sum += (num.charAt(i) - '0');

        // If forward_sum is greater
        // than the previous sum,
        // then call the method again
        if (sum >= previous_sum)

        // Note : We pass current 
        // sum as previous sum
        res += countGroups(i + 1, sum, 
                         length, num);
    }

    // Total number of subgroups
    // till current position
    return res;
}

// Driver Code
public static void main (String[] args)
{
    String num = "1119";
    int len =num .length();
    System.out.println(countGroups(0, 0, 
                                   len, num));
}
}

// This code is contributed by anuj_67.

PHP


<?php
// PHP program to count number of
// ways to group digits of a number 
// such that sum of digits in every 
// subgroup is less than or equal 
// to its immediate right subgroup.

// Function to find the subgroups
function countGroups($position, 
                     $previous_sum, 
                     $length,$num)
{
    // Terminating Condition
    if ($position == $length)
        return 1;

    $res = 0;
    
    // sum of digits
    $sum = 0; 

    // Traverse all digits from 
    // current position to rest
    // of the length of string
    for ($i = $position; $i < $length; $i++)
    {
        $sum += ($num[$i] - '0');

        // If forward_sum is greater 
        // than the previous sum,
        // then call the method again
        if ($sum >= $previous_sum)

        // Note : We pass current
        // sum as previous sum
        $res += countGroups($i + 1, $sum, 
                            $length, $num);
    }

    // Total number of subgroups
    // till current position
    return $res;
}

// Driver Code
$num = "1119";
$len = strlen($num);
echo countGroups(0, 0, $len, $num);

// This code is contributed by ajit
?>


Output :

7

If we take a closer look at above recursive solution, we notice that there may be overlapping subproblems. For example, if input number is 12345, then for position = 3 and previous_sum = 3, we recur two times. Similarly for position 4 and previous_sum = 7, we recur two times. Therefore the above solution can be optimized using Dynamic Programming. Below is a Dynamic Programming based solution for this problem.

  1. The maximum sum of digits can be 9*length where ‘length’ is length of input num.
  2. Create a 2D array int dp[MAX][9*MAX] where MAX is maximum possible length of input numebr. A value dp[position][previous] is going to store result for ‘position’ and ‘previous_sum’.
  3. If current subproblem has been evaluated i.e; dp[position][previous_sum] != -1, then use this result, else recursively compute its value.
  4. If by including the current position digit in sum i.e; sum = sum + num[position]-‘0’, sum becomes greater than equal to previous sum, then increment the result and call the problem for next position in the num.
  5. If position == length, then we have been traversed current subgroup successfully and we return 1;

Below is implementation of above algorithm.

C++

// C++ program to count number of 
// ways to group digits of a number
// such that sum of digits in every 
// subgroup is less than or equal
// to its immediate right subgroup.
#include<bits/stdc++.h>
using namespace std;

// Maximum length of 
// input number string
const int MAX = 40;

// A memoization table to store 
// results of subproblems length
// of string is 40 and maximum 
// sum will be 9 * 40 = 360.
int dp[MAX][9*MAX + 1];

// Function to find the count
// of splits with given condition
int countGroups(int position, 
                int previous_sum, 
                int length, char *num)
{
    // Terminating Condition
    if (position == length)
        return 1;

    // If already evaluated for 
    // a given sub problem then
    // return the value
    if (dp[position][previous_sum] != -1)
        return dp[position][previous_sum];

    // countGroups for current 
    // sub-group is 0
    dp[position][previous_sum] = 0;

    int res = 0;
    
    // sum of digits
    int sum = 0; 

    // Traverse all digits from
    // current position to rest
    // of the length of string
    for (int i = position; i < length; i++)
    {
        sum += (num[i] - '0');

        // If forward_sum is greater 
        // than the previous sum,
        // then call the method again
        if (sum >= previous_sum)

        // Note : We pass current
        // sum as previous sum
        res += countGroups(i + 1, sum, 
                           length, num);
    }

    dp[position][previous_sum] = res;

    // total number of subgroups 
    // till current position
    return res;
}

// Driver Code
int main()
{
    char num[] = "1119";
    int len = strlen(num);

    // Initialize dp table
    memset(dp, -1, sizeof(dp));

    cout << countGroups(0, 0, len, num);
    return 0;
}


Output :

 7

This article is contributed by Shashank Mishra ( Gullu ). This article is reviewed by team GeeksForGeeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up

Improved By : jit_t, vt_m




Practice Tags :

Recommended Posts:



4 Average Difficulty : 4/5.0
Based on 21 vote(s)






User Actions