题目
求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路
看了前人的一些思路,感觉很多都不是很清楚,博主想清楚了以后就过来试试自己写一篇博文。
首先遍历查找的效率为O(nlogn),每个数都得检查每个位是否为1,显然不是一个好办法。这道题主要要利用数字的规律进行快速计算,想法是每次计算从个位到最高位的1的个数,累加即可。那么每位1的个数如何计算呢?核心想法就是固定每一位为1,不超过当前数n的情况下其他位最多的可能组合有几种。
以123456为例,个位上1总共出现12346次,即个位的1固定,前面5位为任意数都可以,所以从0到12345共12346种可能。十位出现次数为1235*10,十位的1固定以后,前4位共1235种可能,而个位有10种可能(不必考虑重复,因为计算的是不同位上的1)。依此类推,百位上出现124 * 100个,千位上出现2 * 1000个,而万位上出现10^5个。
但是其实这边根据每位digit的不同需要分类,以数字n=123x56为例,我们探讨百位出现1的个数:
1)x=0时,共123 * 100种可能(前三位固定123时百位不能取1);
2)x=1时,共123 * 100+57种(前三位为123时,百位取1,后面两位共57种可能);
3)x>1时,共124 * 100种。
这样我们不难写出如下的代码:
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int cnt = 0;
int i, a, b, c, d;
for (i=10; i/10<=n; i*=10){
a = n/i;
b = n%i;
c = b/(i/10);
d = b%(i/10);
cnt += a*i/10+(c>1)*i/10+(c==1)*(d+1);
}
return cnt;
}
};
大家如果有什么问题或者有其他思路欢迎和博主讨论哈~