java2快速解决方案_java – 大量计算的最佳和有效的解决方案?

使用查找表计算数字

您可以生成一个表,该表存储有d个数字的整数,其数字总和大于数字x.然后,您可以快速查找10,100,1000 …整数范围内有多少重数.这些表只保存9×d值,因此它们占用的空间非常小,可以快速生成.

然后,要检查B有d个数字的范围AB,您可以构建1到d-1个数字的表,然后将范围AB拆分为10,100,1000 …的块,并查找表格,例如对于范围A = 782,B = 4321:

RANGE DIGITS TARGET LOOKUP VALUE

782 - 789 78x > 6 table[1][ 6] 3

790 - 799 79x > 5 table[1][ 5] 4

800 - 899 8xx >13 table[2][13] 15

900 - 999 9xx >12 table[2][12] 21

1000 - 1999 1xxx >27 table[3][27] 0

2000 - 2999 2xxx >26 table[3][26] 1

3000 - 3999 3xxx >25 table[3][25] 4

4000 - 4099 40xx >24 impossible 0

4100 - 4199 41xx >23 impossible 0

4200 - 4299 42xx >22 impossible 0

4300 - 4309 430x >21 impossible 0

4310 - 4319 431x >20 impossible 0

4320 - 4321 432x >19 impossible 0

--

48

如果第一个和最后一个范围不完整(不是* 0 – * 9),请检查目标的起始值或结束值. (在示例中,2不大于6,因此所有3个重数都包含在范围内.)

生成查找表

对于1位十进制整数,大于值x的整数n是:

x: 0 1 2 3 4 5 6 7 8 9

n: 9 8 7 6 5 4 3 2 1 0

如您所见,通过取n = 9-x可以很容易地计算出来.

对于2位十进制整数,其位数之和大于值x的整数n是:

x: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

n: 99 97 94 90 85 79 72 64 55 45 36 28 21 15 10 6 3 1 0

对于3位十进制整数,其位数之和大于值x的整数n是:

x: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

n: 999 996 990 980 965 944 916 880 835 780 717 648 575 500 425 352 283 220 165 120 84 56 35 20 10 4 1 0

这些序列中的每一个都可以从前一个序列生成:以值10d开始,然后从该值中减去前一个序列(跳过第一个零).例如.从序列中为2位数生成3位数的序列,从103 = 1000开始,然后:

0. 1000 - 1 = 999

1. 999 - 3 = 996

2. 996 - 6 = 990

3. 990 - 10 = 980

4. 980 - 15 = 965

5. 965 - 21 = 944

6. 944 - 28 = 916

7. 916 - 36 = 880

8. 880 - 45 = 835

9. 835 - 55 = 780

10. 780 - 64 + 1 = 717

11. 717 - 72 + 3 = 648

12. 648 - 79 + 6 = 575

13. 575 - 85 + 10 = 500

14. 500 - 90 + 15 = 425

15. 425 - 94 + 21 = 352

16. 352 - 97 + 28 = 283

17. 283 - 99 + 36 = 220

18. 220 - 100 + 45 = 165

19. 165 - 100 + 55 = 120

20. 120 - 100 + 64 = 84

21. 84 - 100 + 72 = 56

22. 56 - 100 + 79 = 35

23. 35 - 100 + 85 = 20

24. 20 - 100 + 90 = 10

25. 10 - 100 + 94 = 4

26. 4 - 100 + 97 = 1

27. 1 - 100 + 99 = 0

顺便说一下,如果使用7以外的值定义“重”数,则可以使用相同的表.

代码示例

下面是一个演示该方法的Javascript代码片段(我不会说Java).它是非常不被优化的,但它在不到0.07ms的时间内完成了0→100,000,000的示例.它也适用于7以外的权重.转换为Java,它应该轻松击败任何实际贯穿数字并检查其权重的算法.

function countHeavy(A, B, weight) {

var a = decimalDigits(A), b = decimalDigits(B); // create arrays

while (a.length < b.length) a.push(0); // add leading zeros

var digits = b.length, table = weightTable(); // create table

var count = 0, diff = B - A + 1, d = 0; // calculate range

for (var i = digits - 1; i >= 0; i--) if (a[i]) d = i; // lowest non-0 digit

while (diff) { // increment a until a=b

while (a[d] == 10) { // move to higher digit

a[d++] = 0;

++a[d]; // carry 1

}

var step = Math.pow(10, d); // value of digit d

if (step <= diff) {

diff -= step;

count += increment(d); // increment digit d

}

else --d; // move to lower digit

}

return count;

function weightTable() { // see above for details

var t = [[],[9,8,7,6,5,4,3,2,1,0]];

for (var i = 2; i < digits; i++) {

var total = Math.pow(10, i), final = total / 10;

t[i] = [];

for (var j = 9 * i; total > 0; --j) {

if (j > 9) total -= t[i - 1][j - 10]; else total -= final;

if (j < 9 * (i - 1)) total += t[i - 1][j];

t[i].push(total);

}

}

return t;

}

function increment(d) {

var sum = 0, size = digits;

for (var i = digits - 1; i >= d; i--) {

if (a[i] == 0 && i == size - 1) size = i; // count used digits

sum += a[i]; // sum of digits

}

++a[d];

var target = weight * size - sum;

if (d == 0) return (target < 0) ? 1 : 0; // if d is lowest digit

if (target < 0) return table[d][0] + 1; // whole range is heavy

return (target > 9 * d) ? 0 : table[d][target]; // use look-up table

}

function decimalDigits(n) {

var array = [];

do {array.push(n % 10);

n = Math.floor(n / 10);

} while (n);

return array;

}

}

document.write("0 → 100,000,000 = " + countHeavy(0, 100000000, 7) + "
");

document.write("782 → 4321 = " + countHeavy(782, 4321, 7) + "
");

document.write("782 → 4321 = " + countHeavy(782, 4321, 5) + " (weight: 5)");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值