整个问题听起来像是:
“我们在输入,K和S上有2个数字。我们想要在输出第一个(最低)K数字上打印,而它们的数字总和恰好是S”
有一个简单的天真算法来解决这个问题(我能够构建和找到)。它的原理是拥有一个函数 bigint digitSum(i),(我写bigint,因为 S 无论如何都不受限制,因为我想要更有效的算法......)这将返回参数号的数字和。我们将从数字0开始,总是递增1,同时将这些数字放在函数中。如果函数返回与 S 相同的总和,请打印该数字并继续,直到我们打印 K 数字。
功能代码在这里:
bigint digitSum(number){
bigint total = 0;
while(number > 0)
{
total += number % 10;
number /= 10;
}
return total;
}
Big-O中的算法渐近复杂度是因为是搜索数字0,1,2,3 ... n的复杂性,直到我们找到完全 K 所需的数字和是我们查找数字和的函数的复杂性,因为它总是将数字除以10.
是否有任何算法或方法可以提高效率?谢谢!
答案 0 :(得分:1)
要解决这些问题,你必须抓住一些规律。例如,构建第一个数字的序列,其数字和为S
S 0 1 .. 9 10 11 12 .. 18 19 20 .. 31 ...
F(S) 0 1 .. 9 19 29 39 .. 99 199 299 .. 4999...
我们可以看到第一个数字可以使用值
找到M = S div 9
R = S mod 9
作为
F(S) = R(9xM) ////concatenation of digit R and M 9s
for S=31 M=3,R=4, and
F(31) = 4(9x3) = 4999 //concatenation of 4 and three nines
因此我们可以确定O(1)中需要的第一个数字。
然后详细说明具有相同数字总和的下一个数字的规则(注意通常N(i+1) = N(i) + 9
)
答案 1 :(得分:1)
这是一种递归算法,可为您提供K
个最小数字,其数字总和为S
。复杂性肯定比你的蛮力算法好,虽然我不确定它在大O符号中是什么。
算法如下:
S
K
这里是Java中的代码:
public static void main(String[] args) {
int[] currentCount = {0};
int k = 10, s = 10;
for(int n = s/9 ; currentCount[0] != 10 ; n++) {
digitSum(new StringBuilder(), n, 0, s, k, currentCount);
}
}
public static void digitSum(StringBuilder subNumber, int nDigit, int currentSum, int s, int k, int[] currentCount) {
if(nDigit == 0) {
if(currentSum == s) {
System.out.println(subNumber);
currentCount[0]++;
}
return;
}
if(currentCount[0] == k) return; //if already have k numbers, terminate
int remaining = s-currentSum;
if(remaining > nDigit*9) return; //if not enough digits to reach S, terminate
final int bound = Integer.min(9, remaining); //what's the largest valid digit
//zero digit is only valid if subNumber != 0
if(subNumber.length()!=0) digitSum(new StringBuilder(subNumber).append('0'), nDigit-1, currentSum, s, k, currentCount);
for(int i = 1 ; i <= bound ; i++) digitSum(new StringBuilder(subNumber).append((char)(i+'0')), nDigit-1, currentSum+i, s, k, currentCount);
}