比如求出1~13的整数中1出现的次数,1~13中包含1的数字有1、10、11、12、13因此共出现6次,把问题更加普遍化,求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)
思路:
参考自博客https://blog.csdn.net/yi_afly/article/details/52012593
按位依次计算,计算出现在个位上1的次数,十位上1的次数......
对于某一位的1的个数如此计算,比如对980332,981332,984332,计算千位上出现1的所有次数:
当前的base为1000,将数据分为三部分,千位之前的为round:98*10000,千位上的元素记为weight为0,1,4;剩余部分记为former为332;
- 第一部分:0~round*(10base)中千位上出现的次数为round*base--->对于数据来说是98*1000= 98000;
- 剩余部分要通过weight来区分
- 如果weight为0,说明剩余部分中没有达到当前位为1的数字,为0
- 如果weight为1,说明剩余部分中当前位出现1的次数位第三部分加1,比如对981332为981000~981332,引起千位出现1的次数为332+1 = 333;
- 如果weight大于1,说明剩余部分中当前位出现1的次数为base的值,对于984332为981000~981999,引起千位出现1的次数为1000;
代码:
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
if(n <= 0)return 0;
int res = 0;
int round = n, base = 1, weight = 0;
//按位依次计算,计算出现在个位上1的次数,十位上1的次数......
while(round > 0){
//该位之前的数字记为round,该位上的数字记为weight,该位上1代表的实际大小记为base
weight = round %10;
round /= 10;
//将n分为round*(10base) + weight*base + 剩余部分(后面几位)
//第一部分0~round*(10base)出现1的次数为round*base
res += round*base;
//如果weight为1,那么第二三部分出现1的次数为第三部分+1(比如剩余部分为332,那么除第一部分外1000~1332在千位上共出现333次1)
if(weight == 1)
res += (n%base) + 1;
//如果weight大于1,那么第二三部分出现1的次数为base(比如,weight为2,剩余部分为332,那么除第一部分外1000~1999在千位上共出现1000次1)
else if(weight>1)
res += base;
base*=10;
}
return res;
}
};