📌  相关文章
📜  计算具有给定约束的数字的数字分组

📅  最后修改于: 2021-04-27 19:00:51             🧑  作者: Mango

我们给了一个由数字组成的字符串,我们可以将这些数字分组为子组(但要保持其原始顺序)。任务是计算分组的数量,以使得对于除最后一个分组以外的每个子分组,子分组中的数字总和小于或等于其右侧紧邻的子分组中的数字总和。 。
例如,数字1119的有效数字分组为(1-11-9)。第一个子组的数字总和是1,下一个子组是2,最后一个子组是9。每个子组的总和小于或等于其直接右数。
例子 :

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
       the 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]

令“长度”为输入数字的长度。递归解决方案是考虑从0个length-1到每个位置。对于每个位置,递归计算其后的所有可能的子组。下面是朴素的递归解决方案的C++实现。

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
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.


Python3
# Python3 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
def 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 in range(position, length):
 
        sum = sum + int(num[i])
        # 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 = res + countGroups(i + 1, sum, length, num)
 
    # Total number of subgroups
    # till the current position
    return res
 
# Driver Code
if __name__=='__main__':
    num = "1119"
    len = len(num)
    print(countGroups(0, 0, len, num))
 
# This code is contributed by
# Sanjit_Prasad


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.
using System;
                     
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[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 num = "1119";
    int len = num.Length;
    Console.Write(countGroups(0, 0, len, num));
}
}
 
// This code is contributed by 29AjayKumar


PHP
= $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
?>


Javascript


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
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;
}


Java
// Java program to count the 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.
class GFG
{
 
// Maximum length of
// input number string
static int MAX = 40;
 
// A memoization table to store
// results of subproblems length
// of string is 40 and maximum
// sum will be 9 * 40 = 360.
static int dp[][] = new int[MAX][9 * MAX + 1];
 
// Function to find the count
// of splits with given condition
static 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
public static void main(String[] args)
{
    char num[] = "1119".toCharArray();
    int len = num.length;
 
    // Initialize dp table
    for(int i = 0; i < dp.length; i++)
    {
        for(int j = 0;j < 9 * MAX + 1; j++){
            dp[i][j] = -1;
        }
    }
    System.out.println(countGroups(0, 0, len, num));
    }
}
 
// This code is contributed by PrinciRaj1992


Python3
# Python3 program to count the 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.
 
# Maximum length of
# input number string
MAX = 40
 
# A memoization table to store
# results of subproblems length
# of string is 40 and maximum
# sum will be 9 * 40 = 360.
dp = [[ -1 for i in range(9 * MAX + 1)]
           for i in range(MAX)]
 
# Function to find the count
# of splits with given condition
def countGroups(position, previous_sum,
                           length, 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
 
    res = 0
 
    # sum of digits
    sum = 0
 
    # Traverse all digits from
    # current position to rest
    # of the length of string
    for i in range(position,length):
        sum += (ord(num[i]) - ord('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 the current position
    return res
 
# Driver Code
num = "1119"
len = len(num)
 
print(countGroups(0, 0, len, num))
 
# This code is contributed by Mohit Kumar


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.
using System;
 
class GFG
{
    // Maximum length of
    // input number string
    static int MAX = 40;
     
    // A memoization table to store
    // results of subproblems length
    // of string is 40 and maximum
    // sum will be 9 * 40 = 360.
    static int[,] dp = new int[MAX, 9 * MAX + 1];
     
    // Function to find the count
    // of splits with given condition
    static 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
    static void Main()
    {
        char[] num = {'1', '1', '1', '9'};
        int len = num.Length;
     
        // Initialize dp table
        for(int i = 0; i < MAX; i++)
            for(int j = 0; j < 9 * MAX + 1; j++)
                dp[i, j] = -1;
     
        Console.Write(countGroups(0, 0, len, num));
    }
}
 
// This code is contributed by DrRoot_


输出 :

7

如果我们仔细研究以上递归解决方案,我们会注意到可能存在重叠的子问题。例如,如果输入数字为12345,则对于position = 3和previous_sum = 3,我们重复两次。同样,对于位置4和previous_sum = 7,我们重复两次。因此,可以使用动态编程来优化上述解决方案。下面是针对此问题的基于动态编程的解决方案。

  1. 最大数字总和可以是9 * length,其中“ length”是输入数字的长度。
  2. 创建一个2D数组int dp [MAX] [9 * MAX],其中MAX是输入数字的最大可能长度。值dp [position] [previous]将存储“ position”和“ previous_sum”的结果。
  3. 如果当前的子问题已经评估过,即; dp [position] [previous_sum]!= -1,然后使用此结果,否则递归计算其值。
  4. 如果在总和中包括当前位置数字,即; sum = sum + num [position]-‘0’,求和变得大于等于先前的总和,然后递增结果并为num中的下一个位置调用问题。
  5. 如果position == length,则我们已成功遍历当前子组,并且返回1;否则,返回0。

下面是上述算法的实现。

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
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;
}

Java

// Java program to count the 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.
class GFG
{
 
// Maximum length of
// input number string
static int MAX = 40;
 
// A memoization table to store
// results of subproblems length
// of string is 40 and maximum
// sum will be 9 * 40 = 360.
static int dp[][] = new int[MAX][9 * MAX + 1];
 
// Function to find the count
// of splits with given condition
static 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
public static void main(String[] args)
{
    char num[] = "1119".toCharArray();
    int len = num.length;
 
    // Initialize dp table
    for(int i = 0; i < dp.length; i++)
    {
        for(int j = 0;j < 9 * MAX + 1; j++){
            dp[i][j] = -1;
        }
    }
    System.out.println(countGroups(0, 0, len, num));
    }
}
 
// This code is contributed by PrinciRaj1992

Python3

# Python3 program to count the 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.
 
# Maximum length of
# input number string
MAX = 40
 
# A memoization table to store
# results of subproblems length
# of string is 40 and maximum
# sum will be 9 * 40 = 360.
dp = [[ -1 for i in range(9 * MAX + 1)]
           for i in range(MAX)]
 
# Function to find the count
# of splits with given condition
def countGroups(position, previous_sum,
                           length, 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
 
    res = 0
 
    # sum of digits
    sum = 0
 
    # Traverse all digits from
    # current position to rest
    # of the length of string
    for i in range(position,length):
        sum += (ord(num[i]) - ord('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 the current position
    return res
 
# Driver Code
num = "1119"
len = len(num)
 
print(countGroups(0, 0, len, num))
 
# This code is contributed by Mohit Kumar

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.
using System;
 
class GFG
{
    // Maximum length of
    // input number string
    static int MAX = 40;
     
    // A memoization table to store
    // results of subproblems length
    // of string is 40 and maximum
    // sum will be 9 * 40 = 360.
    static int[,] dp = new int[MAX, 9 * MAX + 1];
     
    // Function to find the count
    // of splits with given condition
    static 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
    static void Main()
    {
        char[] num = {'1', '1', '1', '9'};
        int len = num.Length;
     
        // Initialize dp table
        for(int i = 0; i < MAX; i++)
            for(int j = 0; j < 9 * MAX + 1; j++)
                dp[i, j] = -1;
     
        Console.Write(countGroups(0, 0, len, num));
    }
}
 
// This code is contributed by DrRoot_

输出 :

7