我正在研究一个问题来计算十进制表示中0到n之间的2的数量,而不使用递归解决方案。我找到了以下解决方案,我正在调试它,我的问题是:seendigits
和语句countof2s += digit * position * pow10_posMinus1
和seendigits = seendigits + pow10_pos * digit
的逻辑含义是什么?如果有人能提供任何见解,那就太棒了。
public static int count2sI(int num) {
int countof2s = 0, digit = 0;
int j = num, seendigits = 0, position = 0, pow10_pos = 1;
/* maintaining this value instead of calling pow() is an 6x perf
* gain (48s -> 8s) pow10_posMinus1. maintaining this value
* instead of calling Numof2s is an 2x perf gain (8s -> 4s).
* overall > 10x speedup */
while (j > 0) {
digit = j % 10;
int pow10_posMinus1 = pow10_pos / 10;
countof2s += digit * position * pow10_posMinus1;
/* we do this if digit <, >, or = 2
* Digit < 2 implies there are no 2s contributed by this
* digit.
* Digit == 2 implies there are 2 * numof2s contributed by
* the previous position + num of 2s contributed by the
* presence of this 2 */
if (digit == 2) {
countof2s += seendigits + 1;
}
/* Digit > 2 implies there are digit * num of 2s by the prev.
* position + 10^position */
else if (digit > 2) {
countof2s += pow10_pos;
}
seendigits = seendigits + pow10_pos * digit;
pow10_pos *= 10;
position++;
j = j / 10;
}
return (countof2s);
}
答案 0 :(得分:1)
数字从右到左处理。对于输入2468,第一次迭代处理数字8,第二次迭代处理4,然后处理4,最后处理2.
变量seendigits
跟踪已经处理过的数字的组合值;例如对于输入2468,四次迭代期间的值将为0,8,68和468.当数字等于2时使用该值(见下文)。
重要的是要注意,在处理数字时,例如在示例2468中的4中,已经计算了范围1到68的低位数的二进制数。此计数用于401到468的范围,因此仍需要计算的是1到400范围内较低位数的两位数,以及1到468范围内当前位数的两位数。这个算法分别完成了这两件事。
计算低位数的两位数在此行中完成:
countof2s += digit * position * pow10_posMinus1;
在第一次迭代中,这会增加0,因为没有较低的数字。在第二次迭代中,这会增加digit * 1 * 1
,因为有1个较低的数字,对于当前数字的每个值,它等于2。在第三次迭代中,这会增加digit * 2 * 10
,因为有2个较低的数字,它们对于当前数字的每个值都等于2次,依此类推......
对于示例输入2468,此行将添加:
迭代1:数字= 8,加:8 * 0 * 0 = 0
迭代2:数字= 6,加:6 * 1 * 1 = 6
迭代3:数字= 4,加:4 * 2 * 10 = 80
迭代4:数字= 2,加:2 * 3 * 100 = 600
e.g。值80是数字1到400的低位数字中的两个数字:
x02,x12,x22,x32,... x92的最低位数
这些发生4次:2到92次,102到192次,202到292次和302到392次
x20,x21,x22,x23,... x29的第二低位数字
这些发生4次:20到29次,120到129次,220到229次和320到329次。
计算当前数字中的两位数是在以下一行中完成的,具体取决于当前数字是大于还是等于2.
if (digit == 2) { countof2s += seendigits + 1; }
else if (digit > 2) { countof2s += pow10_pos; }
如果当前数字大于2,则从1开始向上计数时数字为2的次数仅取决于数字的位置。对于位置0,这会增加+1,以计算数字2;对于位置1,这增加了+10,对于20到29范围内的最高位数;对于位置2,这会增加+100,对于200到299范围内的最高位,依此类推......
对于示例输入2468,此行将添加:
迭代1:数字= 8,加:1
迭代2:数字= 6,加:10
迭代3:数字= 4,加:100
迭代4:数字= 2,加:0(数字不大于2)
如果当前数字等于2,则数字为2时的数字从1开始向上计数等于低数字+ 1的值。
对于示例输入2468,此行将添加:
迭代1:数字= 8,加:0
迭代2:数字= 6,加:0
迭代3:数字= 4,加:0
迭代4:数字= 2,加:469
这是因为当前数字在2000到2468范围内等于2。
<强>更新强>
如果您处理从左到右的数字,该算法更容易理解:(javascript中的示例)
function twosInRange(number) {
var digits = Math.floor(Math.log(number) / Math.log(10));
var count = 0;
for (var pos = digits; pos >= 0; --pos) { // 3, 2, 1, 0
var unit = Math.pow(10, pos); // 1000, 100, 10, 1
var digit = Math.floor(number / unit); // 2, 4, 6, 8
number -= digit * unit; // 468, 68, 8, 0
// COUNT OCCURRENCES IN LOWER DIGITS:
count += digit * pos * (unit / 10); // + 2*3*100, 4*2*10, 6*1*1, 8*0*0
// COUNT OCCURRENCES IN CURRENT DIGIT:
if (digit > 2) count += unit; // + (1000), 100, 10, 1
else if (digit == 2) count += number + 1; // + 469, (69), (9), (1)
}
return (count); // 600 + 80 + 6 + 100 + 10 + 1 + 469
}
document.write(twosInRange(2468)); // = 1266
&#13;