获取所有n位数字,其总和等于给定总和

时间:2018-06-18 14:55:44

标签: c# performance sum-of-digits

如何获得所有n位数字,其总和等于给定总和?我需要最快的解决方案,因为n可以等于9,sum可以等于1000。

我已经实施了下面的解决方案,但它太慢了......

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

2 个答案:

答案 0 :(得分:4)

  

我需要最快的解决方案

不,你需要一个足够快的解决方案。您可能不愿意在自定义硬件上花费一百万美元来获得尽可能快的解决方案。

  

如何获得所有n位数字,其总和等于给定总和?

在这里,我将为您解决一个稍微不同的问题:

  

从0-9中抽取的n位数的所有序列是什么?总和为sum

这是不同的,因为这会将0110计为长度为2的序列,总和为1,但01不是两位数。

我会告诉你如何解决这个更容易的问题。 然后您采用该解决方案并使其适应您更难的问题

首先,您能解决一位数的问题吗?这很简单。如果n为0到9,则数字总和为n的一位数字是数字n,否则没有解决方案。

第二:假设n> 1.然后总和为n的{​​{1}}位数字为:

  • sum后跟所有0个数字,总计为n-1
  • sum后跟所有1个数字,总计为n-1
  • sum-1后跟所有2个数字,总计为n-1
  • ...
  • sum-2后跟所有9个数字,总计为n-1

编写一个解决该问题的实现,然后对其进行调整以解决您的问题。

答案 1 :(得分:0)

您可以将n位数字视为n位数组。然后,您可以将特定数字增加到下一个数字,该数字也会加起来。逐步完成所有下一个答案,您已经生成了所有可能的组合。

使用生成器将每个n位组合作为IEnumerable<int>(实际上是int[]),您可以从&#34;最小的&#34;开始。 n位组合,产生总和,并通过每一个。

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

这比我的递归双生成器解决方案(有点像@ EricLippert的建议)要快得多,以迭代所有可能性(例如使用Count())。

您可以将数字重新组合在一起,以获得每个数字的最终数字字符串:

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