简体   繁体   中英

Get all n-digit numbers whose sum of digits equals to given sum

How can I get all n-digit numbers whose sum of digits equals to given sum? I need the fastest solution because n can be equal with 9 and sum can be equal with 1000.

I have implemented the solution below but it's too slow...

List<int> l = new List<int>();
void findNDigitNumsUtil(int n, int sum, char[] ou, int index)
{
    if (index > n || sum < 0)
        return;
    if (index == n)
    {
        if (sum == 0)
        {
            ou[index] = '\0';
            string s = new string(ou);
            l.Add(Int32.Parse(s));
        }

        return;
    }

    for (int i = 0; i <= 9; i++)
    {
        ou[index] = (char)(i + '0');
        findNDigitNumsUtil(n, sum - i, ou,
                                index + 1);

    }
}

void findNDigitNums(int n, int sum)
{
    char[] ou = new char[n + 1];
    for (int i = 1; i <= 9; i++)
    {
        ou[0] = (char)(i + '0');
        findNDigitNumsUtil(n, sum - i, ou, 1);
    }
}

I need the fastest solution

No, you need a fast-enough solution. You are probably unwilling to spend even a million dollars on custom hardware to get the fastest possible solution.

How can I get all n-digit numbers whose sum of digits equals to given sum?

Here, I'll give you the solution for a slightly different problem:

What are all the sequences of n digits drawn from 0-9 that sum to sum ?

This is different because this counts 01 and 10 as sequences of length two that sum to 1, but 01 is not a two-digit number.

I'll give you a hint for how to solve this easier problem. You then take that solution and adapt it to your harder problem .

First, can you solve the problem for one-digit numbers ? That's pretty easy. The one-digit numbers whose digits sum to n are the digit n if n is 0 through 9, and there is no solution otherwise.

Second: Suppose n > 1. Then the n -digit numbers that sum to sum are:

  • 0 followed by all the n-1 digit numbers that sum to sum
  • 1 followed by all the n-1 digit numbers that sum to sum-1
  • 2 followed by all the n-1 digit numbers that sum to sum-2
  • ...
  • 9 followed by all the n-1 digit numbers that sum to sum-9

Write an implementation that solves that problem, and then adapt it to solve your problem.

You can treat n-digit number as an array of n digits. Then you can increment a particular number to the next number that also adds up to the sum. Stepping through all the next answers, you have generated all possible combinations.

Using a generator to yield each n-digit combination as an IEnumerable<int> (in fact, an int[] ), you start with the "smallest" n-digit combination that yields the sum, and go through each one.

IEnumerable<IEnumerable<int>> DigitsToSum(int n, int sum) {
    if (sum > 9 * n)
        yield return Enumerable.Empty<int>();
    else {
        var ans = new int[n];

        void distribute(int wsum, int downto) {
            for (var j1 = n - 1; j1 > downto; --j1) {
                if (wsum > 9) {
                    ans[j1] = 9;
                    wsum -= 9;
                }
                else {
                    ans[j1] = wsum;
                    wsum = 0;
                }
            }
        }

        ans[0] = Math.Max(1, sum-9*(n-1));
        distribute(sum-ans[0], 0);

        bool nextAns() {
            var wsum = ans[n-1];
            for (var j1 = n - 2; j1 >= 0; --j1) {
                wsum += ans[j1];

                if (ans[j1] < Math.Min(9, wsum)) {
                    ++ans[j1];
                    distribute(wsum - ans[j1], j1);
                    return true;
                }
            }
            return false;
        }

        do {
            yield return ans;
        } while (nextAns());
    }
}

This is tremendously faster than my recursive double generator solution (somewhat like @EricLippert's suggestion) to iterate over all possibilities (eg using Count() ).

You can put the digits back together to get a final numeric string for each number:

var ans = DigitsToSum(n, sum).Select(p => String.Join("", p));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM