剑指offer31 ——整数中1出现的次数(从1到n整数中1出现的次数)
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
这道题抛开暴力解法不提是真的难,至少对我来说
做这道题首先要知道的“常识”:
1~10的个位1出现的次数是1
1~100的十位1出现的次数是10
1~1000的百位1出现的次数是100
1~10000的千位1出现的次数是1000
…
比如20个位数1出现的次数是20/10=2,(1,11)
当然这是整数好说,如果是21,22,23的话就是20/10+1=3(1,11,21),就是说如果不是正好的话,还要分情况
下面举例子:(1)125,105,115这三个数求它的十位出现的1的次数,先121/100=1,有1个100,根据上面的“常识”,只看整数的话它有1*10个。
(2)再看余数超过等于20的肯定有10~19十位出现1,共10个,比如125就是这样。如果余数超过等于10并且小于20的要看十位后面的数,比如115,就有10 ~15共5+1=6。最后看余数小于10的,也就是上面剩下的,比如105,十位为1个数为0。
最后把(1)(2)部分相加就是数的十位出现1的次数。
其他百位、千位的都是同理。
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int count=0;
for(int i=1;i<=n;i*=10)
{
count+=n/(i*10)*i; //求i位整除部分的1的次数(算十位时125/100有一个100,要乘10)
if(n%(i*10)>=2*i) //i位余数部分是否>=2*i,如果是则是固定的i(125)
{
count+=i;
}
else if(n%(i*10)>=i) //如果不是且>=i,则看i位以后的所有位数,+1表示本身(115十位的10)
{
count+=n%(i*10)%i+1;
}
//剩下的十位一定没有(105)
}
return count;