题目:输入一个整数m,求从1到n这n个整数的十进制表示中k出现的次数。例如输入一个12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次。
思路:分别统计k出现在个位,十位,百位,千位...的个数。
n = 2593, x = 5 为例来解释如何得到数学公式。从 1 至 2593中,数字 5 总计出现了 813 次,其中有 259次出现在个位,260次出现在十位,294次出现在百位,0次出现在千位。
- 现在依次分析这些数据,首先是个位。从 1 至 2590 中,包含了 259 个 10,因此任意的 x 都出现了 259 次。最后剩余的三个数 2531,2592,2593,因为它们最大的个位数字 3 < x。因此不会包含任何 5. (也可以这么看, 3 < x, 则个位上可能出现的 x 的位数由更高位决定,等于更高位数字 (259) * 101-1 = 259)。
- 然后是十位。从 1 至 2500中,包含了25个100,因此任意的 x 都出现了 25 * 10 = 250 次。剩下的数字从 2501 至 2593,它们最大的十位数是 9 > x,因此会包含全部 10 个 5。最后总计 250 + 10 = 260。(也可以这么看,9 > x,则十位上可能出现的 x 的位数由更高位决定,等于更高位数字(25 + 1) * 102-1 = 260。
- 接下来是百位。从1至2000中,包含了2个1000,因此任意x都出现了2 * 100 = 200次。剩下的数字从2001至2593,它们最大的百位数字5 == x,这时候情况就略微复杂,它们的百位肯定是包含5的,但是不会包含全部100个。如果把百位是5的列出来,是从2500至2593,数字的个数与十位和个位数字有关,是93 + 1 = 94。最后总计 200 + 94 = 294。(也可以这么看, 5 == x,则百位上可能出现的x次数不仅受跟高位影响,还受低位影响,等于更高位数字 2 * 103-1 + (93 + 1))。
- 最后是千位,现在已经没有更高位,因此直接看最大的千位数字 2 < x,因此不会包含任何 5 。(也可以这么看,2 < x,则千位上可能出现的x的次数仅由更高位决定,等于更高位数字 0 * 104-1 = 0)
注意:不能直接用每个数去除以10的幂计算1的个数。
public int NumBetweenKAndN(int n, int k) { if (n < k) return 0; if (n >= k && n <= 9) return 1; int i = 1; int res = 0; while (i < n) { int high = n / i; // 最高位 res += high * i / 10; int nn = n % i * 10 / i; // 除去最高位的余数 if (nn == k) // 余数的最高位等于k res += n % i - nn * i / 10; if (nn > k) // 余数的最高位大于k res += (i / 10); i *= 10; // 省去pow运算 } return res; }
参考:https://www.cnblogs.com/lengender-12/p/6876897.html